From 504bae3b992280dc4d9ede22387dbd3a39670308 Mon Sep 17 00:00:00 2001 From: monyarm Date: Fri, 15 May 2020 05:14:45 +0300 Subject: [PATCH 1/2] Started work on porting vileVN games --- .clang-format | 3 - base/commandLine.cpp | 1 + engines/vileVN/common/cfg.cpp | 65 + engines/vileVN/common/cfg.h | 89 + engines/vileVN/common/config.h.in | 199 + engines/vileVN/common/darray.cpp | 192 + engines/vileVN/common/darray.h | 35 + engines/vileVN/common/dbuffer.cpp | 74 + engines/vileVN/common/dbuffer.h | 29 + engines/vileVN/common/dstack.cpp | 135 + engines/vileVN/common/dstack.h | 30 + engines/vileVN/common/dvector.cpp | 396 + engines/vileVN/common/dvector.h | 48 + engines/vileVN/common/edl_common.cpp | 335 + engines/vileVN/common/edl_common.h | 69 + engines/vileVN/common/edl_fs.cpp | 687 ++ engines/vileVN/common/edl_fs.h | 57 + engines/vileVN/common/edl_gfx.cpp | 957 +++ engines/vileVN/common/edl_gfx.h | 84 + engines/vileVN/common/guicon.cpp | 50 + engines/vileVN/common/guicon.h | 16 + engines/vileVN/common/inifile.cpp | 348 + engines/vileVN/common/inifile.h | 40 + engines/vileVN/common/log.cpp | 200 + engines/vileVN/common/log.h | 70 + engines/vileVN/common/redblack.cpp | 404 + engines/vileVN/common/redblack.h | 70 + engines/vileVN/common/savegame.cpp | 617 ++ engines/vileVN/common/savegame.h | 69 + engines/vileVN/common/stringlist.cpp | 162 + engines/vileVN/common/stringlist.h | 31 + engines/vileVN/common/ustring.cpp | 651 ++ engines/vileVN/common/ustring.h | 131 + engines/vileVN/configure.engine | 3 + engines/vileVN/cware/cware.cpp | 778 ++ engines/vileVN/cware/cware.h | 98 + engines/vileVN/cware/cwaremap.cpp | 129 + engines/vileVN/cware/cwaremap.h | 36 + engines/vileVN/cware/dividead/divicg.cpp | 162 + engines/vileVN/cware/dividead/divicg.h | 20 + engines/vileVN/cware/dividead/dividead.cpp | 295 + engines/vileVN/cware/dividead/dividead.h | 36 + engines/vileVN/cware/dividead/divigui.cpp | 79 + engines/vileVN/cware/dividead/divigui.h | 24 + engines/vileVN/cware/dividead/divimenu.cpp | 119 + engines/vileVN/cware/dividead/divimenu.h | 29 + engines/vileVN/detection.cpp | 182 + engines/vileVN/dialogs/dlgbase.cpp | 630 ++ engines/vileVN/dialogs/dlgbase.h | 106 + engines/vileVN/dialogs/fatal.cpp | 37 + engines/vileVN/dialogs/fatal.h | 19 + engines/vileVN/dialogs/options.cpp | 251 + engines/vileVN/dialogs/options.h | 38 + engines/vileVN/dialogs/popimage.cpp | 136 + engines/vileVN/dialogs/popimage.h | 26 + engines/vileVN/dialogs/selection.cpp | 198 + engines/vileVN/dialogs/selection.h | 43 + engines/vileVN/dialogs/stdhalt.cpp | 85 + engines/vileVN/dialogs/stdhalt.h | 27 + engines/vileVN/dialogs/stdload.cpp | 42 + engines/vileVN/dialogs/stdload.h | 18 + engines/vileVN/dialogs/stdmenu.cpp | 121 + engines/vileVN/dialogs/stdmenu.h | 39 + engines/vileVN/dialogs/stdmsg.cpp | 90 + engines/vileVN/dialogs/stdmsg.h | 24 + engines/vileVN/dialogs/stdsave.cpp | 240 + engines/vileVN/dialogs/stdsave.h | 33 + engines/vileVN/dialogs/stdtitle.cpp | 154 + engines/vileVN/dialogs/stdtitle.h | 47 + engines/vileVN/dialogs/textview.cpp | 289 + engines/vileVN/dialogs/textview.h | 79 + engines/vileVN/engine/crenderer.cpp | 123 + engines/vileVN/engine/crenderer.h | 36 + engines/vileVN/engine/ebase.cpp | 970 +++ engines/vileVN/engine/ebase.h | 177 + engines/vileVN/engine/emixer.cpp | 445 + engines/vileVN/engine/emixer.h | 78 + engines/vileVN/engine/evideo.cpp | 260 + engines/vileVN/engine/evideo.h | 71 + engines/vileVN/engine/evn.cpp | 736 ++ engines/vileVN/engine/evn.h | 149 + engines/vileVN/engine/renderer.cpp | 161 + engines/vileVN/engine/renderer.h | 50 + engines/vileVN/engine/sequencer.cpp | 295 + engines/vileVN/engine/sequencer.h | 40 + .../vileVN/external/SDL/gfx/SDL_framerate.c | 135 + .../vileVN/external/SDL/gfx/SDL_framerate.h | 79 + .../vileVN/external/SDL/gfx/SDL_gfxBlitFunc.c | 576 ++ .../vileVN/external/SDL/gfx/SDL_gfxBlitFunc.h | 144 + .../external/SDL/gfx/SDL_gfxPrimitives.c | 6755 +++++++++++++++ .../external/SDL/gfx/SDL_gfxPrimitives.h | 225 + .../vileVN/external/SDL/gfx/SDL_imageFilter.c | 7556 +++++++++++++++++ .../vileVN/external/SDL/gfx/SDL_imageFilter.h | 195 + .../vileVN/external/SDL/gfx/SDL_rotozoom.c | 1638 ++++ .../vileVN/external/SDL/gfx/SDL_rotozoom.h | 103 + engines/vileVN/external/SDL/image/IMG.c | 212 + engines/vileVN/external/SDL/image/IMG_bmp.c | 848 ++ engines/vileVN/external/SDL/image/IMG_gif.c | 625 ++ engines/vileVN/external/SDL/image/IMG_jpg.c | 495 ++ engines/vileVN/external/SDL/image/IMG_lbm.c | 503 ++ engines/vileVN/external/SDL/image/IMG_pcx.c | 276 + engines/vileVN/external/SDL/image/IMG_png.c | 578 ++ engines/vileVN/external/SDL/image/IMG_pnm.c | 258 + engines/vileVN/external/SDL/image/IMG_tga.c | 336 + engines/vileVN/external/SDL/image/IMG_tif.c | 298 + engines/vileVN/external/SDL/image/IMG_webp.c | 295 + engines/vileVN/external/SDL/image/IMG_xcf.c | 824 ++ engines/vileVN/external/SDL/image/IMG_xpm.c | 514 ++ engines/vileVN/external/SDL/image/IMG_xv.c | 165 + engines/vileVN/external/SDL/image/SDL_image.h | 138 + engines/vileVN/external/SDL/ttf/SDL_ttf.c | 2052 +++++ engines/vileVN/external/SDL/ttf/SDL_ttf.h | 249 + engines/vileVN/external/hq2x/hq2x.cpp | 2891 +++++++ engines/vileVN/external/hq2x/hq2x.h | 9 + engines/vileVN/external/hq3x/hq3x.cpp | 3849 +++++++++ engines/vileVN/external/hq3x/hq3x.h | 9 + engines/vileVN/external/hq4x/hq4x.cpp | 5314 ++++++++++++ engines/vileVN/external/hq4x/hq4x.h | 9 + engines/vileVN/external/utf8cpp/checked.h | 327 + engines/vileVN/external/utf8cpp/core.h | 358 + engines/vileVN/external/utf8cpp/unchecked.h | 228 + engines/vileVN/ikura/catgirl/catgirl.cpp | 111 + engines/vileVN/ikura/catgirl/catgirl.h | 22 + engines/vileVN/ikura/crescendo/crescendo.cpp | 49 + engines/vileVN/ikura/crescendo/crescendo.h | 22 + engines/vileVN/ikura/drsdecoder.cpp | 508 ++ engines/vileVN/ikura/drsdecoder.h | 54 + engines/vileVN/ikura/hitomi/hitomi.cpp | 112 + engines/vileVN/ikura/hitomi/hitomi.h | 22 + engines/vileVN/ikura/idisplay.cpp | 483 ++ engines/vileVN/ikura/idisplay.h | 69 + engines/vileVN/ikura/idols/idols.cpp | 81 + engines/vileVN/ikura/idols/idols.h | 22 + engines/vileVN/ikura/ikuradecoder.cpp | 2045 +++++ engines/vileVN/ikura/ikuradecoder.h | 189 + engines/vileVN/ikura/iopcodes.h | 199 + engines/vileVN/ikura/iparser.cpp | 320 + engines/vileVN/ikura/iparser.h | 50 + engines/vileVN/ikura/iscript.cpp | 396 + engines/vileVN/ikura/iscript.h | 66 + engines/vileVN/ikura/kana/kana.cpp | 42 + engines/vileVN/ikura/kana/kana.h | 19 + engines/vileVN/ikura/kanaoka/kanaoka.cpp | 53 + engines/vileVN/ikura/kanaoka/kanaoka.h | 19 + engines/vileVN/ikura/sagara/sagara.cpp | 489 ++ engines/vileVN/ikura/sagara/sagara.h | 22 + engines/vileVN/ikura/snow/snow.cpp | 92 + engines/vileVN/ikura/snow/snow.h | 17 + engines/vileVN/jast/jast.cpp | 1408 +++ engines/vileVN/jast/jast.h | 120 + engines/vileVN/jast/jumc.cpp | 97 + engines/vileVN/jast/jumc.h | 35 + engines/vileVN/jast/jumcmain.cpp | 175 + engines/vileVN/jast/jumcmain.h | 41 + engines/vileVN/media/affmpeg.cpp | 629 ++ engines/vileVN/media/affmpeg.h | 83 + engines/vileVN/media/afluid.cpp | 241 + engines/vileVN/media/afluid.h | 39 + engines/vileVN/media/audio.cpp | 41 + engines/vileVN/media/audio.h | 37 + engines/vileVN/media/vffmpeg.cpp | 539 ++ engines/vileVN/media/vffmpeg.h | 67 + engines/vileVN/media/video.cpp | 28 + engines/vileVN/media/video.h | 29 + engines/vileVN/module.mk | 15 + engines/vileVN/res/archives/abase.cpp | 165 + engines/vileVN/res/archives/abase.h | 59 + engines/vileVN/res/archives/acrowdpck.cpp | 110 + engines/vileVN/res/archives/acrowdpck.h | 17 + engines/vileVN/res/archives/acrowdsce.cpp | 191 + engines/vileVN/res/archives/acrowdsce.h | 27 + engines/vileVN/res/archives/acrowdsnn.cpp | 48 + engines/vileVN/res/archives/acrowdsnn.h | 15 + engines/vileVN/res/archives/acwarearc2.cpp | 51 + engines/vileVN/res/archives/acwarearc2.h | 15 + engines/vileVN/res/archives/acwaredl1.cpp | 45 + engines/vileVN/res/archives/acwaredl1.h | 15 + engines/vileVN/res/archives/afiles.cpp | 63 + engines/vileVN/res/archives/afiles.h | 16 + engines/vileVN/res/archives/aikura.cpp | 104 + engines/vileVN/res/archives/aikura.h | 15 + engines/vileVN/res/archives/aitem.cpp | 95 + engines/vileVN/res/archives/aitem.h | 54 + engines/vileVN/res/archives/ajast.cpp | 92 + engines/vileVN/res/archives/ajast.h | 17 + engines/vileVN/res/archives/as21.cpp | 38 + engines/vileVN/res/archives/as21.h | 15 + engines/vileVN/res/archives/atlove.cpp | 96 + engines/vileVN/res/archives/atlove.h | 15 + engines/vileVN/res/archives/avile.cpp | 47 + engines/vileVN/res/archives/avile.h | 15 + engines/vileVN/res/archives/awillarc.cpp | 68 + engines/vileVN/res/archives/awillarc.h | 15 + engines/vileVN/res/archives/awindy.cpp | 64 + engines/vileVN/res/archives/awindy.h | 15 + engines/vileVN/res/cache.cpp | 97 + engines/vileVN/res/cache.h | 40 + engines/vileVN/res/converters/ccrowd.cpp | 201 + engines/vileVN/res/converters/ccrowd.h | 16 + engines/vileVN/res/converters/ccware.cpp | 76 + engines/vileVN/res/converters/ccware.h | 17 + engines/vileVN/res/converters/cikura.cpp | 768 ++ engines/vileVN/res/converters/cikura.h | 26 + engines/vileVN/res/converters/ctlove.cpp | 144 + engines/vileVN/res/converters/ctlove.h | 15 + engines/vileVN/res/converters/cwill.cpp | 210 + engines/vileVN/res/converters/cwill.h | 19 + engines/vileVN/res/converters/cwindy.cpp | 165 + engines/vileVN/res/converters/cwindy.h | 17 + engines/vileVN/res/media.cpp | 67 + engines/vileVN/res/media.h | 29 + engines/vileVN/res/resources.cpp | 470 + engines/vileVN/res/resources.h | 71 + engines/vileVN/res/rwops.cpp | 295 + engines/vileVN/res/rwops.h | 46 + engines/vileVN/testing/benchmark.cpp | 68 + engines/vileVN/testing/benchmark.h | 27 + engines/vileVN/testing/coretest.cpp | 199 + engines/vileVN/testing/coretest.h | 12 + engines/vileVN/testing/filetest.cpp | 438 + engines/vileVN/testing/filetest.h | 12 + engines/vileVN/testing/gfxbench.cpp | 69 + engines/vileVN/testing/gfxbench.h | 12 + engines/vileVN/testing/miscbench.cpp | 40 + engines/vileVN/testing/miscbench.h | 12 + engines/vileVN/testing/misctest.cpp | 210 + engines/vileVN/testing/misctest.h | 12 + engines/vileVN/testing/rwtest.cpp | 86 + engines/vileVN/testing/rwtest.h | 14 + engines/vileVN/testing/utest.cpp | 112 + engines/vileVN/testing/utest.h | 42 + engines/vileVN/tlove/tlove.cpp | 1236 +++ engines/vileVN/tlove/tlove.h | 154 + engines/vileVN/vile.cpp | 877 ++ engines/vileVN/vile.h | 103 + engines/vileVN/widgets/animation.cpp | 49 + engines/vileVN/widgets/animation.h | 20 + engines/vileVN/widgets/bbutton.cpp | 214 + engines/vileVN/widgets/bbutton.h | 31 + engines/vileVN/widgets/checkbox.cpp | 101 + engines/vileVN/widgets/checkbox.h | 26 + engines/vileVN/widgets/fade.cpp | 174 + engines/vileVN/widgets/fade.h | 47 + engines/vileVN/widgets/group.cpp | 372 + engines/vileVN/widgets/group.h | 66 + engines/vileVN/widgets/hotspot.cpp | 29 + engines/vileVN/widgets/hotspot.h | 16 + engines/vileVN/widgets/mwidget.cpp | 49 + engines/vileVN/widgets/mwidget.h | 30 + engines/vileVN/widgets/printer.cpp | 476 ++ engines/vileVN/widgets/printer.h | 65 + engines/vileVN/widgets/saveslab.cpp | 222 + engines/vileVN/widgets/saveslab.h | 38 + engines/vileVN/widgets/scroll.cpp | 122 + engines/vileVN/widgets/scroll.h | 34 + engines/vileVN/widgets/slide.cpp | 113 + engines/vileVN/widgets/slide.h | 27 + engines/vileVN/widgets/slider.cpp | 194 + engines/vileVN/widgets/slider.h | 35 + engines/vileVN/widgets/sprite.cpp | 106 + engines/vileVN/widgets/sprite.h | 31 + engines/vileVN/widgets/swidget.cpp | 81 + engines/vileVN/widgets/swidget.h | 40 + engines/vileVN/widgets/tbutton.cpp | 216 + engines/vileVN/widgets/tbutton.h | 58 + engines/vileVN/widgets/vbutton.cpp | 143 + engines/vileVN/widgets/vbutton.h | 32 + engines/vileVN/widgets/vwidget.cpp | 49 + engines/vileVN/widgets/vwidget.h | 31 + engines/vileVN/widgets/widget.cpp | 539 ++ engines/vileVN/widgets/widget.h | 128 + engines/vileVN/widgets/zoom.cpp | 192 + engines/vileVN/widgets/zoom.h | 32 + engines/vileVN/will/critical/critical.cpp | 53 + engines/vileVN/will/critical/critical.h | 26 + engines/vileVN/will/will.cpp | 1395 +++ engines/vileVN/will/will.h | 147 + engines/vileVN/will/yume/yume.cpp | 55 + engines/vileVN/will/yume/yume.h | 23 + engines/vileVN/will/yume/yumetv.cpp | 167 + engines/vileVN/will/yume/yumetv.h | 41 + engines/vileVN/windy/mayclub/mayclub.cpp | 567 ++ engines/vileVN/windy/mayclub/mayclub.h | 57 + engines/vileVN/windy/mayclub/mcalbum.cpp | 434 + engines/vileVN/windy/mayclub/mcalbum.h | 42 + engines/vileVN/windy/mayclub/mcback.cpp | 114 + engines/vileVN/windy/mayclub/mcback.h | 25 + engines/vileVN/windy/mayclub/mcload.cpp | 219 + engines/vileVN/windy/mayclub/mcload.h | 29 + engines/vileVN/windy/mayclub/mcmain.cpp | 178 + engines/vileVN/windy/mayclub/mcmain.h | 23 + engines/vileVN/windy/mayclub/mcsave.cpp | 219 + engines/vileVN/windy/mayclub/mcsave.h | 29 + engines/vileVN/windy/mayclub/mctv.cpp | 255 + engines/vileVN/windy/mayclub/mctv.h | 37 + engines/vileVN/windy/mayclub/mcwhisper.cpp | 311 + engines/vileVN/windy/mayclub/mcwhisper.h | 37 + engines/vileVN/windy/nocturnal/niload.cpp | 119 + engines/vileVN/windy/nocturnal/niload.h | 22 + engines/vileVN/windy/nocturnal/niloc.cpp | 344 + engines/vileVN/windy/nocturnal/niloc.h | 21 + engines/vileVN/windy/nocturnal/nimain.cpp | 87 + engines/vileVN/windy/nocturnal/nimain.h | 23 + .../vileVN/windy/nocturnal/niremenisce.cpp | 383 + engines/vileVN/windy/nocturnal/niremenisce.h | 34 + engines/vileVN/windy/nocturnal/nisave.cpp | 119 + engines/vileVN/windy/nocturnal/nisave.h | 22 + engines/vileVN/windy/nocturnal/nocturnal.cpp | 622 ++ engines/vileVN/windy/nocturnal/nocturnal.h | 52 + engines/vileVN/windy/whisper.cpp | 95 + engines/vileVN/windy/whisper.h | 42 + engines/vileVN/windy/windy.cpp | 1718 ++++ engines/vileVN/windy/windy.h | 193 + 313 files changed, 83690 insertions(+), 3 deletions(-) create mode 100644 engines/vileVN/common/cfg.cpp create mode 100644 engines/vileVN/common/cfg.h create mode 100644 engines/vileVN/common/config.h.in create mode 100644 engines/vileVN/common/darray.cpp create mode 100644 engines/vileVN/common/darray.h create mode 100644 engines/vileVN/common/dbuffer.cpp create mode 100644 engines/vileVN/common/dbuffer.h create mode 100644 engines/vileVN/common/dstack.cpp create mode 100644 engines/vileVN/common/dstack.h create mode 100644 engines/vileVN/common/dvector.cpp create mode 100644 engines/vileVN/common/dvector.h create mode 100644 engines/vileVN/common/edl_common.cpp create mode 100644 engines/vileVN/common/edl_common.h create mode 100644 engines/vileVN/common/edl_fs.cpp create mode 100644 engines/vileVN/common/edl_fs.h create mode 100644 engines/vileVN/common/edl_gfx.cpp create mode 100644 engines/vileVN/common/edl_gfx.h create mode 100644 engines/vileVN/common/guicon.cpp create mode 100644 engines/vileVN/common/guicon.h create mode 100644 engines/vileVN/common/inifile.cpp create mode 100644 engines/vileVN/common/inifile.h create mode 100644 engines/vileVN/common/log.cpp create mode 100644 engines/vileVN/common/log.h create mode 100644 engines/vileVN/common/redblack.cpp create mode 100644 engines/vileVN/common/redblack.h create mode 100644 engines/vileVN/common/savegame.cpp create mode 100644 engines/vileVN/common/savegame.h create mode 100644 engines/vileVN/common/stringlist.cpp create mode 100644 engines/vileVN/common/stringlist.h create mode 100644 engines/vileVN/common/ustring.cpp create mode 100644 engines/vileVN/common/ustring.h create mode 100644 engines/vileVN/configure.engine create mode 100644 engines/vileVN/cware/cware.cpp create mode 100644 engines/vileVN/cware/cware.h create mode 100644 engines/vileVN/cware/cwaremap.cpp create mode 100644 engines/vileVN/cware/cwaremap.h create mode 100644 engines/vileVN/cware/dividead/divicg.cpp create mode 100644 engines/vileVN/cware/dividead/divicg.h create mode 100644 engines/vileVN/cware/dividead/dividead.cpp create mode 100644 engines/vileVN/cware/dividead/dividead.h create mode 100644 engines/vileVN/cware/dividead/divigui.cpp create mode 100644 engines/vileVN/cware/dividead/divigui.h create mode 100644 engines/vileVN/cware/dividead/divimenu.cpp create mode 100644 engines/vileVN/cware/dividead/divimenu.h create mode 100644 engines/vileVN/detection.cpp create mode 100644 engines/vileVN/dialogs/dlgbase.cpp create mode 100644 engines/vileVN/dialogs/dlgbase.h create mode 100644 engines/vileVN/dialogs/fatal.cpp create mode 100644 engines/vileVN/dialogs/fatal.h create mode 100644 engines/vileVN/dialogs/options.cpp create mode 100644 engines/vileVN/dialogs/options.h create mode 100644 engines/vileVN/dialogs/popimage.cpp create mode 100644 engines/vileVN/dialogs/popimage.h create mode 100644 engines/vileVN/dialogs/selection.cpp create mode 100644 engines/vileVN/dialogs/selection.h create mode 100644 engines/vileVN/dialogs/stdhalt.cpp create mode 100644 engines/vileVN/dialogs/stdhalt.h create mode 100644 engines/vileVN/dialogs/stdload.cpp create mode 100644 engines/vileVN/dialogs/stdload.h create mode 100644 engines/vileVN/dialogs/stdmenu.cpp create mode 100644 engines/vileVN/dialogs/stdmenu.h create mode 100644 engines/vileVN/dialogs/stdmsg.cpp create mode 100644 engines/vileVN/dialogs/stdmsg.h create mode 100644 engines/vileVN/dialogs/stdsave.cpp create mode 100644 engines/vileVN/dialogs/stdsave.h create mode 100644 engines/vileVN/dialogs/stdtitle.cpp create mode 100644 engines/vileVN/dialogs/stdtitle.h create mode 100644 engines/vileVN/dialogs/textview.cpp create mode 100644 engines/vileVN/dialogs/textview.h create mode 100644 engines/vileVN/engine/crenderer.cpp create mode 100644 engines/vileVN/engine/crenderer.h create mode 100644 engines/vileVN/engine/ebase.cpp create mode 100644 engines/vileVN/engine/ebase.h create mode 100644 engines/vileVN/engine/emixer.cpp create mode 100644 engines/vileVN/engine/emixer.h create mode 100644 engines/vileVN/engine/evideo.cpp create mode 100644 engines/vileVN/engine/evideo.h create mode 100644 engines/vileVN/engine/evn.cpp create mode 100644 engines/vileVN/engine/evn.h create mode 100644 engines/vileVN/engine/renderer.cpp create mode 100644 engines/vileVN/engine/renderer.h create mode 100644 engines/vileVN/engine/sequencer.cpp create mode 100644 engines/vileVN/engine/sequencer.h create mode 100644 engines/vileVN/external/SDL/gfx/SDL_framerate.c create mode 100644 engines/vileVN/external/SDL/gfx/SDL_framerate.h create mode 100644 engines/vileVN/external/SDL/gfx/SDL_gfxBlitFunc.c create mode 100644 engines/vileVN/external/SDL/gfx/SDL_gfxBlitFunc.h create mode 100644 engines/vileVN/external/SDL/gfx/SDL_gfxPrimitives.c create mode 100644 engines/vileVN/external/SDL/gfx/SDL_gfxPrimitives.h create mode 100644 engines/vileVN/external/SDL/gfx/SDL_imageFilter.c create mode 100644 engines/vileVN/external/SDL/gfx/SDL_imageFilter.h create mode 100644 engines/vileVN/external/SDL/gfx/SDL_rotozoom.c create mode 100644 engines/vileVN/external/SDL/gfx/SDL_rotozoom.h create mode 100644 engines/vileVN/external/SDL/image/IMG.c create mode 100644 engines/vileVN/external/SDL/image/IMG_bmp.c create mode 100644 engines/vileVN/external/SDL/image/IMG_gif.c create mode 100644 engines/vileVN/external/SDL/image/IMG_jpg.c create mode 100644 engines/vileVN/external/SDL/image/IMG_lbm.c create mode 100644 engines/vileVN/external/SDL/image/IMG_pcx.c create mode 100644 engines/vileVN/external/SDL/image/IMG_png.c create mode 100644 engines/vileVN/external/SDL/image/IMG_pnm.c create mode 100644 engines/vileVN/external/SDL/image/IMG_tga.c create mode 100644 engines/vileVN/external/SDL/image/IMG_tif.c create mode 100644 engines/vileVN/external/SDL/image/IMG_webp.c create mode 100644 engines/vileVN/external/SDL/image/IMG_xcf.c create mode 100644 engines/vileVN/external/SDL/image/IMG_xpm.c create mode 100644 engines/vileVN/external/SDL/image/IMG_xv.c create mode 100644 engines/vileVN/external/SDL/image/SDL_image.h create mode 100644 engines/vileVN/external/SDL/ttf/SDL_ttf.c create mode 100644 engines/vileVN/external/SDL/ttf/SDL_ttf.h create mode 100644 engines/vileVN/external/hq2x/hq2x.cpp create mode 100644 engines/vileVN/external/hq2x/hq2x.h create mode 100644 engines/vileVN/external/hq3x/hq3x.cpp create mode 100644 engines/vileVN/external/hq3x/hq3x.h create mode 100644 engines/vileVN/external/hq4x/hq4x.cpp create mode 100644 engines/vileVN/external/hq4x/hq4x.h create mode 100644 engines/vileVN/external/utf8cpp/checked.h create mode 100755 engines/vileVN/external/utf8cpp/core.h create mode 100755 engines/vileVN/external/utf8cpp/unchecked.h create mode 100644 engines/vileVN/ikura/catgirl/catgirl.cpp create mode 100644 engines/vileVN/ikura/catgirl/catgirl.h create mode 100644 engines/vileVN/ikura/crescendo/crescendo.cpp create mode 100644 engines/vileVN/ikura/crescendo/crescendo.h create mode 100644 engines/vileVN/ikura/drsdecoder.cpp create mode 100644 engines/vileVN/ikura/drsdecoder.h create mode 100644 engines/vileVN/ikura/hitomi/hitomi.cpp create mode 100644 engines/vileVN/ikura/hitomi/hitomi.h create mode 100644 engines/vileVN/ikura/idisplay.cpp create mode 100644 engines/vileVN/ikura/idisplay.h create mode 100644 engines/vileVN/ikura/idols/idols.cpp create mode 100644 engines/vileVN/ikura/idols/idols.h create mode 100644 engines/vileVN/ikura/ikuradecoder.cpp create mode 100644 engines/vileVN/ikura/ikuradecoder.h create mode 100644 engines/vileVN/ikura/iopcodes.h create mode 100644 engines/vileVN/ikura/iparser.cpp create mode 100644 engines/vileVN/ikura/iparser.h create mode 100644 engines/vileVN/ikura/iscript.cpp create mode 100644 engines/vileVN/ikura/iscript.h create mode 100644 engines/vileVN/ikura/kana/kana.cpp create mode 100644 engines/vileVN/ikura/kana/kana.h create mode 100644 engines/vileVN/ikura/kanaoka/kanaoka.cpp create mode 100644 engines/vileVN/ikura/kanaoka/kanaoka.h create mode 100644 engines/vileVN/ikura/sagara/sagara.cpp create mode 100644 engines/vileVN/ikura/sagara/sagara.h create mode 100644 engines/vileVN/ikura/snow/snow.cpp create mode 100644 engines/vileVN/ikura/snow/snow.h create mode 100644 engines/vileVN/jast/jast.cpp create mode 100644 engines/vileVN/jast/jast.h create mode 100644 engines/vileVN/jast/jumc.cpp create mode 100644 engines/vileVN/jast/jumc.h create mode 100644 engines/vileVN/jast/jumcmain.cpp create mode 100644 engines/vileVN/jast/jumcmain.h create mode 100644 engines/vileVN/media/affmpeg.cpp create mode 100644 engines/vileVN/media/affmpeg.h create mode 100644 engines/vileVN/media/afluid.cpp create mode 100644 engines/vileVN/media/afluid.h create mode 100644 engines/vileVN/media/audio.cpp create mode 100644 engines/vileVN/media/audio.h create mode 100644 engines/vileVN/media/vffmpeg.cpp create mode 100644 engines/vileVN/media/vffmpeg.h create mode 100644 engines/vileVN/media/video.cpp create mode 100644 engines/vileVN/media/video.h create mode 100644 engines/vileVN/module.mk create mode 100644 engines/vileVN/res/archives/abase.cpp create mode 100644 engines/vileVN/res/archives/abase.h create mode 100644 engines/vileVN/res/archives/acrowdpck.cpp create mode 100644 engines/vileVN/res/archives/acrowdpck.h create mode 100644 engines/vileVN/res/archives/acrowdsce.cpp create mode 100644 engines/vileVN/res/archives/acrowdsce.h create mode 100644 engines/vileVN/res/archives/acrowdsnn.cpp create mode 100644 engines/vileVN/res/archives/acrowdsnn.h create mode 100644 engines/vileVN/res/archives/acwarearc2.cpp create mode 100644 engines/vileVN/res/archives/acwarearc2.h create mode 100644 engines/vileVN/res/archives/acwaredl1.cpp create mode 100644 engines/vileVN/res/archives/acwaredl1.h create mode 100644 engines/vileVN/res/archives/afiles.cpp create mode 100644 engines/vileVN/res/archives/afiles.h create mode 100644 engines/vileVN/res/archives/aikura.cpp create mode 100644 engines/vileVN/res/archives/aikura.h create mode 100644 engines/vileVN/res/archives/aitem.cpp create mode 100644 engines/vileVN/res/archives/aitem.h create mode 100644 engines/vileVN/res/archives/ajast.cpp create mode 100644 engines/vileVN/res/archives/ajast.h create mode 100644 engines/vileVN/res/archives/as21.cpp create mode 100644 engines/vileVN/res/archives/as21.h create mode 100644 engines/vileVN/res/archives/atlove.cpp create mode 100644 engines/vileVN/res/archives/atlove.h create mode 100644 engines/vileVN/res/archives/avile.cpp create mode 100644 engines/vileVN/res/archives/avile.h create mode 100644 engines/vileVN/res/archives/awillarc.cpp create mode 100644 engines/vileVN/res/archives/awillarc.h create mode 100644 engines/vileVN/res/archives/awindy.cpp create mode 100644 engines/vileVN/res/archives/awindy.h create mode 100644 engines/vileVN/res/cache.cpp create mode 100644 engines/vileVN/res/cache.h create mode 100644 engines/vileVN/res/converters/ccrowd.cpp create mode 100644 engines/vileVN/res/converters/ccrowd.h create mode 100644 engines/vileVN/res/converters/ccware.cpp create mode 100644 engines/vileVN/res/converters/ccware.h create mode 100644 engines/vileVN/res/converters/cikura.cpp create mode 100644 engines/vileVN/res/converters/cikura.h create mode 100644 engines/vileVN/res/converters/ctlove.cpp create mode 100644 engines/vileVN/res/converters/ctlove.h create mode 100644 engines/vileVN/res/converters/cwill.cpp create mode 100644 engines/vileVN/res/converters/cwill.h create mode 100644 engines/vileVN/res/converters/cwindy.cpp create mode 100644 engines/vileVN/res/converters/cwindy.h create mode 100644 engines/vileVN/res/media.cpp create mode 100644 engines/vileVN/res/media.h create mode 100644 engines/vileVN/res/resources.cpp create mode 100644 engines/vileVN/res/resources.h create mode 100644 engines/vileVN/res/rwops.cpp create mode 100644 engines/vileVN/res/rwops.h create mode 100644 engines/vileVN/testing/benchmark.cpp create mode 100644 engines/vileVN/testing/benchmark.h create mode 100644 engines/vileVN/testing/coretest.cpp create mode 100644 engines/vileVN/testing/coretest.h create mode 100644 engines/vileVN/testing/filetest.cpp create mode 100644 engines/vileVN/testing/filetest.h create mode 100644 engines/vileVN/testing/gfxbench.cpp create mode 100644 engines/vileVN/testing/gfxbench.h create mode 100644 engines/vileVN/testing/miscbench.cpp create mode 100644 engines/vileVN/testing/miscbench.h create mode 100644 engines/vileVN/testing/misctest.cpp create mode 100644 engines/vileVN/testing/misctest.h create mode 100644 engines/vileVN/testing/rwtest.cpp create mode 100644 engines/vileVN/testing/rwtest.h create mode 100644 engines/vileVN/testing/utest.cpp create mode 100644 engines/vileVN/testing/utest.h create mode 100644 engines/vileVN/tlove/tlove.cpp create mode 100644 engines/vileVN/tlove/tlove.h create mode 100644 engines/vileVN/vile.cpp create mode 100644 engines/vileVN/vile.h create mode 100644 engines/vileVN/widgets/animation.cpp create mode 100644 engines/vileVN/widgets/animation.h create mode 100644 engines/vileVN/widgets/bbutton.cpp create mode 100644 engines/vileVN/widgets/bbutton.h create mode 100644 engines/vileVN/widgets/checkbox.cpp create mode 100644 engines/vileVN/widgets/checkbox.h create mode 100644 engines/vileVN/widgets/fade.cpp create mode 100644 engines/vileVN/widgets/fade.h create mode 100644 engines/vileVN/widgets/group.cpp create mode 100644 engines/vileVN/widgets/group.h create mode 100644 engines/vileVN/widgets/hotspot.cpp create mode 100644 engines/vileVN/widgets/hotspot.h create mode 100644 engines/vileVN/widgets/mwidget.cpp create mode 100644 engines/vileVN/widgets/mwidget.h create mode 100644 engines/vileVN/widgets/printer.cpp create mode 100644 engines/vileVN/widgets/printer.h create mode 100644 engines/vileVN/widgets/saveslab.cpp create mode 100644 engines/vileVN/widgets/saveslab.h create mode 100644 engines/vileVN/widgets/scroll.cpp create mode 100644 engines/vileVN/widgets/scroll.h create mode 100644 engines/vileVN/widgets/slide.cpp create mode 100644 engines/vileVN/widgets/slide.h create mode 100644 engines/vileVN/widgets/slider.cpp create mode 100644 engines/vileVN/widgets/slider.h create mode 100644 engines/vileVN/widgets/sprite.cpp create mode 100644 engines/vileVN/widgets/sprite.h create mode 100644 engines/vileVN/widgets/swidget.cpp create mode 100644 engines/vileVN/widgets/swidget.h create mode 100644 engines/vileVN/widgets/tbutton.cpp create mode 100644 engines/vileVN/widgets/tbutton.h create mode 100644 engines/vileVN/widgets/vbutton.cpp create mode 100644 engines/vileVN/widgets/vbutton.h create mode 100644 engines/vileVN/widgets/vwidget.cpp create mode 100644 engines/vileVN/widgets/vwidget.h create mode 100644 engines/vileVN/widgets/widget.cpp create mode 100644 engines/vileVN/widgets/widget.h create mode 100644 engines/vileVN/widgets/zoom.cpp create mode 100644 engines/vileVN/widgets/zoom.h create mode 100644 engines/vileVN/will/critical/critical.cpp create mode 100644 engines/vileVN/will/critical/critical.h create mode 100644 engines/vileVN/will/will.cpp create mode 100644 engines/vileVN/will/will.h create mode 100644 engines/vileVN/will/yume/yume.cpp create mode 100644 engines/vileVN/will/yume/yume.h create mode 100644 engines/vileVN/will/yume/yumetv.cpp create mode 100644 engines/vileVN/will/yume/yumetv.h create mode 100644 engines/vileVN/windy/mayclub/mayclub.cpp create mode 100644 engines/vileVN/windy/mayclub/mayclub.h create mode 100644 engines/vileVN/windy/mayclub/mcalbum.cpp create mode 100644 engines/vileVN/windy/mayclub/mcalbum.h create mode 100644 engines/vileVN/windy/mayclub/mcback.cpp create mode 100644 engines/vileVN/windy/mayclub/mcback.h create mode 100644 engines/vileVN/windy/mayclub/mcload.cpp create mode 100644 engines/vileVN/windy/mayclub/mcload.h create mode 100644 engines/vileVN/windy/mayclub/mcmain.cpp create mode 100644 engines/vileVN/windy/mayclub/mcmain.h create mode 100644 engines/vileVN/windy/mayclub/mcsave.cpp create mode 100644 engines/vileVN/windy/mayclub/mcsave.h create mode 100644 engines/vileVN/windy/mayclub/mctv.cpp create mode 100644 engines/vileVN/windy/mayclub/mctv.h create mode 100644 engines/vileVN/windy/mayclub/mcwhisper.cpp create mode 100644 engines/vileVN/windy/mayclub/mcwhisper.h create mode 100644 engines/vileVN/windy/nocturnal/niload.cpp create mode 100644 engines/vileVN/windy/nocturnal/niload.h create mode 100644 engines/vileVN/windy/nocturnal/niloc.cpp create mode 100644 engines/vileVN/windy/nocturnal/niloc.h create mode 100644 engines/vileVN/windy/nocturnal/nimain.cpp create mode 100644 engines/vileVN/windy/nocturnal/nimain.h create mode 100644 engines/vileVN/windy/nocturnal/niremenisce.cpp create mode 100644 engines/vileVN/windy/nocturnal/niremenisce.h create mode 100644 engines/vileVN/windy/nocturnal/nisave.cpp create mode 100644 engines/vileVN/windy/nocturnal/nisave.h create mode 100644 engines/vileVN/windy/nocturnal/nocturnal.cpp create mode 100644 engines/vileVN/windy/nocturnal/nocturnal.h create mode 100644 engines/vileVN/windy/whisper.cpp create mode 100644 engines/vileVN/windy/whisper.h create mode 100644 engines/vileVN/windy/windy.cpp create mode 100644 engines/vileVN/windy/windy.h diff --git a/.clang-format b/.clang-format index a11dad4393..f452328b57 100644 --- a/.clang-format +++ b/.clang-format @@ -15,10 +15,7 @@ SpaceBeforeAssignmentOperators: true, SpaceBeforeCtorInitializerColon: true, SpaceBeforeInheritanceColon: true, - SpaceBeforeSquareBrackets: false, SpaceInEmptyParentheses: false, SpacesInAngles: false, - SpacesInConditionalStatement: false, SpacesInParentheses: false, - SpacesInSquareBrackets: false, } diff --git a/base/commandLine.cpp b/base/commandLine.cpp index c768d89293..1c39ec0f78 100644 --- a/base/commandLine.cpp +++ b/base/commandLine.cpp @@ -26,6 +26,7 @@ #define FORBIDDEN_SYMBOL_EXCEPTION_exit #include +#include #include "engines/metaengine.h" #include "base/commandLine.h" diff --git a/engines/vileVN/common/cfg.cpp b/engines/vileVN/common/cfg.cpp new file mode 100644 index 0000000000..f272348b6d --- /dev/null +++ b/engines/vileVN/common/cfg.cpp @@ -0,0 +1,65 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "cfg.h" + +// Preffered video settings +int Cfg::Display::Width=0; +int Cfg::Display::Height=0; +int Cfg::Display::Depth=32; +//int Cfg::Display::Flags=SDL_HWSURFACE|SDL_DOUBLEBUF; +int Cfg::Display::Flags=SDL_HWSURFACE; + +// Audio settings +int Cfg::Audio::Frequency=22050; +int Cfg::Audio::Buffersize=1024; +int Cfg::Audio::Buffercount=6; +int Cfg::Audio::Channels=2; +int Cfg::Audio::CDROM=-1; +bool Cfg::Audio::Enabled=true; +uString Cfg::Audio::Soundfont="GeneralUser GS FluidSynth v1.43.sf2"; + +// Video configuration +bool Cfg::Video::Overlay=true; +int Cfg::Video::Framecount=6; +bool Cfg::Video::Enabled=true; + +// Default system settings +uString Cfg::System::Logfile=""; +uString Cfg::System::Keyfile=""; +bool Cfg::System::Logcolor=false; +bool Cfg::System::Verbose=false; +bool Cfg::System::Mainmenu=true; +int Cfg::System::Framerate=25; + +// Default paths (Defaults from build enviroment) +uString Cfg::Path::cwd=VILE_PATH_CWD; +uString Cfg::Path::game=VILE_PATH_GAME; +uString Cfg::Path::save=VILE_PATH_SAVE; +uString Cfg::Path::config=VILE_PATH_CFG; +uString Cfg::Path::resource=VILE_PATH_RES; + +// Default font configuration +uString Cfg::Font::default_face="Ubuntu-B.ttf"; +int Cfg::Font::default_size=18; +int Cfg::Font::default_style=0; + +// Default color scheme +Uint32 Cfg::Color::DialogBackground=0xFFFFFFC0; +Uint32 Cfg::Color::DialogHeader=0xA00000FF; +Uint32 Cfg::Color::DialogTopic=0x000000FF; +Uint32 Cfg::Color::WidgetBackground=0x00000000; +Uint32 Cfg::Color::WidgetFont=0x404040FF; + diff --git a/engines/vileVN/common/cfg.h b/engines/vileVN/common/cfg.h new file mode 100644 index 0000000000..5207cdda30 --- /dev/null +++ b/engines/vileVN/common/cfg.h @@ -0,0 +1,89 @@ +/*! \class Cfg + * \brief Global configuration + * + * Collects and categorizes the common configuration (eg. across titles). + * The defaults are set in Cfg.cpp and can typically be overridden by the + * commandline handler. + * + * Game options such as volume settings are stored in the savegames. + * + */ +#ifndef _CFG_H_ +#define _CFG_H_ + +#include +#include "ustring.h" + +class Cfg { + public: + // Settings for the physical display + class Display { + public: + static int Width; //!< Display width + static int Height; //!< Display height + static int Depth; //!< Display depth + static int Flags; //!< SDL flags for display + }; + + // Audio settings + class Audio { + public: + static bool Enabled; //!< Wether to load audio + static int Frequency; //!< Samples per second + static int Buffersize; //!< Samples per buffer + static int Buffercount; //!< Frames in buffer + static int Channels; //!< Number of channels + static int CDROM; //!< CD drive (-1 for none) + static uString Soundfont; //!< Default soundfont + }; + + // Video configuration + class Video { + public: + static bool Enabled; //!< Wether to load video + static bool Overlay; //!< Use overlayed video + static int Framecount; //!< Frames in buffer + }; + + // Generic system settings + class System { + public: + static uString Logfile; //!< Output file + static uString Keyfile; //!< Script encryption file + static bool Logcolor; //!< Print colored messages + static bool Verbose; //!< Print verbose messages + static bool Mainmenu; //!< Load main menu + static int Framerate; //!< Limits fps + }; + + // Paths to key files and directories + class Path { + public: + static uString cwd; //!< Working directory + static uString game; //!< Game resource folder + static uString save; //!< Savegame folder + static uString config; //!< Configuration file + static uString resource; //!< Resource file + }; + + // Font configuration + class Font { + public: + // Default for anything else + static uString default_face; //!< Default font file + static int default_size; //!< Default font size + static int default_style; //!< Default font style + }; + + class Color { + public: + static Uint32 DialogBackground; //!< Dialog background + static Uint32 DialogHeader; //!< Header font color + static Uint32 DialogTopic; //!< Subheader font color + static Uint32 WidgetBackground; //!< widget background + static Uint32 WidgetFont; //!< widget font color + }; +}; + +#endif + diff --git a/engines/vileVN/common/config.h.in b/engines/vileVN/common/config.h.in new file mode 100644 index 0000000000..e5e86ec2be --- /dev/null +++ b/engines/vileVN/common/config.h.in @@ -0,0 +1,199 @@ +/* src/common/config.h.in. Generated from configure.ac by autoheader. */ + +/* Compilation date */ +#undef COMPILATION_DATE + +/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ +#undef HAVE_DOPRNT + +/* Handles timezone and days */ +#undef HAVE_GETTIMEOFDAY + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Updates blocks of ram */ +#undef HAVE_MEMSET + +/* Define to 1 if stdbool.h conforms to C99. */ +#undef HAVE_STDBOOL_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_SELECT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_SOCKET_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define to 1 if you have the `vprintf' function. */ +#undef HAVE_VPRINTF + +/* Updates blocks of ram */ +#undef HAVE_WORDEXP_H + +/* Define to 1 if the system has the type `_Bool'. */ +#undef HAVE__BOOL + +/* Name of package */ +#undef PACKAGE + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Name of current line */ +#undef PACKAGE_LINE + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the home page for this package. */ +#undef PACKAGE_URL + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* SCM Revision */ +#undef SCM_VERSION + +/* Define to the type of arg 1 for `select'. */ +#undef SELECT_TYPE_ARG1 + +/* Define to the type of args 2, 3 and 4 for `select'. */ +#undef SELECT_TYPE_ARG234 + +/* Define to the type of arg 5 for `select'. */ +#undef SELECT_TYPE_ARG5 + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Define to 1 if you can safely include both and . */ +#undef TIME_WITH_SYS_TIME + +/* Define to 1 if your declares `struct tm'. */ +#undef TM_IN_SYS_TIME + +/* Version number of package */ +#undef VERSION + +/* Compile code for a BSD based target */ +#undef VILE_ARCH_FREEBSD + +/* Compile code for a linuxbased target */ +#undef VILE_ARCH_LINUX + +/* Compile code for wintendo */ +#undef VILE_ARCH_MICROSOFT + +/* Use internal SDL_gfx code (Not library) */ +#undef VILE_BUILD_INTERNALGFX + +/* Use internal SDL_image code (Not library) */ +#undef VILE_BUILD_INTERNALIMAGE + +/* Use internal SDL_ttf code (Not library) */ +#undef VILE_BUILD_INTERNALTTF + +/* Build a native msys makefile */ +#undef VILE_BUILD_MSYS + +/* Enabling SDL 1.3 support */ +#undef VILE_BUILD_SDLHG + +/* Build standalone executable */ +#undef VILE_BUILD_STATIC + +/* Enabling UNICODE support */ +#undef VILE_BUILD_UNICODE + +/* Build with win32 console */ +#undef VILE_BUILD_W32CONSOLE + +/* Building with Electric Fence enabled */ +#undef VILE_FEATURE_EFENCE + +/* Building with ffmpeg */ +#undef VILE_FEATURE_FFMPEG + +/* Building with fluidsynth */ +#undef VILE_FEATURE_FLUIDSYNTH + +/* Building with hq scalers enabled */ +#undef VILE_FEATURE_SCALER + +/* Building with unittests enabled */ +#undef VILE_FEATURE_UNITTEST + +/* Build with debug information */ +#undef VILE_LOGGING_DEBUG + +/* Build with logging information */ +#undef VILE_LOGGING_ENABLED + +/* Default configuration file */ +#undef VILE_PATH_CFG + +/* Current working directory */ +#undef VILE_PATH_CWD + +/* Default path to load games from */ +#undef VILE_PATH_GAME + +/* Default resource file */ +#undef VILE_PATH_RES + +/* Default path for savegames */ +#undef VILE_PATH_SAVE + +/* Building with crowd support */ +#undef VILE_SUPPORT_CROWD + +/* Building with cware support */ +#undef VILE_SUPPORT_CWARE + +/* Building with ikura support */ +#undef VILE_SUPPORT_IKURA + +/* Building with jast support */ +#undef VILE_SUPPORT_JAST + +/* Building with True love support */ +#undef VILE_SUPPORT_TLOVE + +/* Building with will support */ +#undef VILE_SUPPORT_WILL + +/* Building with windy support */ +#undef VILE_SUPPORT_WINDY + +/* Define to empty if `const' does not conform to ANSI C. */ +#undef const diff --git a/engines/vileVN/common/darray.cpp b/engines/vileVN/common/darray.cpp new file mode 100644 index 0000000000..bc1aca3d03 --- /dev/null +++ b/engines/vileVN/common/darray.cpp @@ -0,0 +1,192 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "darray.h" + +DArray::DArray(const DArray &Src){ + vectors=0; + len=0; + (*this)=Src; +} + +DArray::DArray(int Width,int Height){ + if(Width>0 && Height>0){ + len=Width; + vectors=new DVector*[len]; + for(int i=0;i=len){ + int i; + DVector **newvectors=new DVector*[Index+1]; + for(i=0;iSetUint32(SubIndex,Value); +} + +void DArray::SetUint16(int Index,int SubIndex,Uint16 Value){ + assertvector(Index); + vectors[Index]->SetUint16(SubIndex,Value); +} + +void DArray::SetUint8(int Index,int SubIndex,Uint8 Value){ + assertvector(Index); + vectors[Index]->SetUint8(SubIndex,Value); +} + +void DArray::SetSint32(int Index,int SubIndex,Sint32 Value){ + assertvector(Index); + vectors[Index]->SetSint32(SubIndex,Value); +} + +void DArray::SetSint16(int Index,int SubIndex,Sint16 Value){ + assertvector(Index); + vectors[Index]->SetSint16(SubIndex,Value); +} + +void DArray::SetSint8(int Index,int SubIndex,Sint8 Value){ + assertvector(Index); + vectors[Index]->SetSint8(SubIndex,Value); +} + +void DArray::SetBit(int Index,int SubIndex,bool Value){ + assertvector(Index); + vectors[Index]->SetBit(SubIndex,Value); +} + +Uint32 DArray::GetUint32(int Index,int SubIndex){ + if(IndexGetUint32(SubIndex); + } + else{ + return 0; + } +} + +Uint16 DArray::GetUint16(int Index,int SubIndex){ + if(IndexGetUint16(SubIndex); + } + else{ + return 0; + } +} + + +Uint8 DArray::GetUint8(int Index,int SubIndex){ + if(IndexGetUint8(SubIndex); + } + else{ + return 0; + } +} + + +Sint32 DArray::GetSint32(int Index,int SubIndex){ + if(IndexGetSint32(SubIndex); + } + else{ + return 0; + } +} + + +Sint16 DArray::GetSint16(int Index,int SubIndex){ + if(IndexGetSint16(SubIndex); + } + else{ + return 0; + } +} + + +Sint8 DArray::GetSint8(int Index,int SubIndex){ + if(IndexGetSint8(SubIndex); + } + else{ + return 0; + } +} + + +bool DArray::GetBit(int Index,int SubIndex){ + if(IndexGetBit(SubIndex); + } + else{ + return 0; + } +} + + + diff --git a/engines/vileVN/common/darray.h b/engines/vileVN/common/darray.h new file mode 100644 index 0000000000..412f15a50d --- /dev/null +++ b/engines/vileVN/common/darray.h @@ -0,0 +1,35 @@ +/*! \class DArray + * \brief Dynamic array that grows as needed + */ +#ifndef _DARRAY_H_ +#define _DARRAY_H_ + +#include "dvector.h" + +class DArray { + private: + DVector **vectors; + int len; + void assertvector(int Index); + public: + DArray(const DArray &Src); + DArray(int Width=0,int Height=0); + ~DArray(); + DArray& operator=(const DArray &Src); + void SetUint32(int Index,int SubIndex,Uint32 Value); + void SetUint16(int Index,int SubIndex,Uint16 Value); + void SetUint8(int Index,int SubIndex,Uint8 Value); + void SetSint32(int Index,int SubIndex,Sint32 Value); + void SetSint16(int Index,int SubIndex,Sint16 Value); + void SetSint8(int Index,int SubIndex,Sint8 Value); + void SetBit(int Index,int SubIndex,bool Value); + Uint32 GetUint32(int Index,int SubIndex); + Uint16 GetUint16(int Index,int SubIndex); + Uint8 GetUint8(int Index,int SubIndex); + Sint32 GetSint32(int Index,int SubIndex); + Sint16 GetSint16(int Index,int SubIndex); + Sint8 GetSint8(int Index,int SubIndex); + bool GetBit(int Index,int SubIndex); +}; + +#endif diff --git a/engines/vileVN/common/dbuffer.cpp b/engines/vileVN/common/dbuffer.cpp new file mode 100644 index 0000000000..45c0550e8c --- /dev/null +++ b/engines/vileVN/common/dbuffer.cpp @@ -0,0 +1,74 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "dbuffer.h" + +DBuffer::DBuffer(){ + buffers=0; + sizes=0; + size=0; +} + +DBuffer::~DBuffer(){ + if(buffers){ + for(int i=0;i=size){ + // Rebuild a new bufferbuffer + int i=0; + Uint8 **newbuffers=new Uint8*[Index+1]; + int *newsizes=new int[Index+1]; + for(i=0;i +#include "log.h" + +class DBuffer { + private: + Uint8 **buffers; //!< Holds stored buffers + int *sizes; //!< Holds sizes of stored buffers + int size; //!< Number of stored buffers + public: + DBuffer(); + ~DBuffer(); + void SetBuffer(int Index,Uint8 *Buffer,int Size); + bool GetBuffer(int Index,Uint8 **Buffer,int *Size); +}; + +#endif + diff --git a/engines/vileVN/common/dstack.cpp b/engines/vileVN/common/dstack.cpp new file mode 100644 index 0000000000..739c140790 --- /dev/null +++ b/engines/vileVN/common/dstack.cpp @@ -0,0 +1,135 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "dstack.h" + +DStack::DStack(){ + // Set defaults + Head.Object=0; + Head.Nextptr=0; +} + +DStack::~DStack(){ + Flush(); +} + +void DStack::Flush(){ + // Delete stack objects (NOT objects!) + while(Head.Nextptr){ + STACK_TYPE *tmpptr=Head.Nextptr->Nextptr; + delete Head.Nextptr; + Head.Nextptr=tmpptr; + } +} + + +int DStack::Count(){ + int retval=0; + STACK_TYPE *tmpptr=&Head; + while(tmpptr->Nextptr){ + tmpptr=tmpptr->Nextptr; + retval++; + } + return retval; +} + +/*! \brief Place an object at the top of the stack + * \param Object to put in the stack + */ +void DStack::Push(void *Object){ + STACK_TYPE *tmpptr=Head.Nextptr; + Head.Nextptr=new STACK_TYPE; + Head.Nextptr->Nextptr=tmpptr; + Head.Nextptr->Object=Object; +} + +/*! \brief Place an object at the bottom of the stack + * \param Object to put in the stack + */ +void DStack::Queue(void *Object){ + STACK_TYPE *tmpptr=&Head; + while(tmpptr->Nextptr){ + tmpptr=tmpptr->Nextptr; + } + tmpptr->Nextptr=new STACK_TYPE; + tmpptr->Nextptr->Nextptr=0; + tmpptr->Nextptr->Object=Object; +} + +/*! \brief Finds the top object on the stack + * \return Found object + */ +void *DStack::Peek(){ + void *retval=0; + if(Head.Nextptr){ + retval=Head.Nextptr->Object; + } + return retval; +} + +/*! \brief Finds an indexed object on the stack + * \return Found object + */ +void *DStack::Get(int Index){ + void *retval=0; + STACK_TYPE *tmpptr=Head.Nextptr; + for(int i=0;iNextptr; + } + if(tmpptr){ + retval=tmpptr->Object; + } + return retval; +} + +void *DStack::Drop(int Index){ + void *retval=0; + if(Index){ + STACK_TYPE *tmpptr=Head.Nextptr; + for(int i=1;iNextptr; + } + if(tmpptr && tmpptr->Nextptr){ + STACK_TYPE *swapptr=tmpptr->Nextptr->Nextptr; + retval=tmpptr->Nextptr->Object; + delete tmpptr->Nextptr; + tmpptr->Nextptr=swapptr; + } + } + else if(Head.Nextptr){ + STACK_TYPE *tmpptr=Head.Nextptr->Nextptr; + retval=Head.Nextptr->Object; + delete Head.Nextptr; + Head.Nextptr=tmpptr; + + } + return retval; +} + + +/*! \brief Finds and removes the top object on the stack + * \return Removed object + */ +void *DStack::Pop(){ + void *retval=0; + if(Head.Nextptr){ + STACK_TYPE *tmpptr=Head.Nextptr; + Head.Nextptr=tmpptr->Nextptr; + retval=tmpptr->Object; + delete tmpptr; + } + return retval; +} + diff --git a/engines/vileVN/common/dstack.h b/engines/vileVN/common/dstack.h new file mode 100644 index 0000000000..2615dbd50f --- /dev/null +++ b/engines/vileVN/common/dstack.h @@ -0,0 +1,30 @@ +/*! \class DStack + * \brief Simple stacking mechanism + */ +#ifndef _DSTACK_H_ +#define _DSTACK_H_ + +#include +#include "log.h" + +class DStack { + private: + struct STACK_TYPE { + void *Object; + STACK_TYPE *Nextptr; + }Head; + public: + DStack(); + ~DStack(); + int Count(); + void Push(void *Object); + void Queue(void *Object); + void *Get(int Index); + void *Drop(int Index); + void *Pop(); + void *Peek(); + void Flush(); +}; + +#endif + diff --git a/engines/vileVN/common/dvector.cpp b/engines/vileVN/common/dvector.cpp new file mode 100644 index 0000000000..29d5b8e847 --- /dev/null +++ b/engines/vileVN/common/dvector.cpp @@ -0,0 +1,396 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "dvector.h" + +/*! \brief Creates a new DVector and copy the content from an existing one + * \param DVector Source vector + */ +DVector::DVector(const DVector &Src){ + reg=0; + len=0; + (*this)=Src; +} + +/*! \brief Creates a new vector with a preallocated start size + * \param Preload Number of bytes to preallocate + * + * The preallocated bytes are all set to NULL. You can preallocate a smaller + * or bigger buffer, but dynamic growing/and schrinking the buffer takes a + * lot of time and resources so a "correct" size is much more efficient. + */ +DVector::DVector(int Preload){ + if(Preload){ + len=Preload; + reg=new Uint8[len]; + for(Uint32 i=0;i=len){ + return false; + } + else{ + return reg[bytepos]&(1<=len){ + // Resize buffer + Uint8 *tmpbit=new Uint8[bytepos+1]; + for(Uint32 i=0;i=len){ + // Resize buffer + Uint8 *tmp8=new Uint8[Pos+1]; + for(Uint32 i=0;i=len16){ + // Resize buffer + Uint16 *tmp16=new Uint16[Pos+1]; + for(Uint32 i=0;i=len32){ + // Resize buffer + Uint32 *tmp32=new Uint32[Pos+1]; + for(Uint32 i=0;i +#include "log.h" + +class DVector { + private: + Uint8 *reg; + Uint32 len; + public: + DVector(const DVector &Src); + DVector(int Preload=0); + ~DVector(); + + // Normal value API + void SetUint32(Uint32 Pos,Uint32 Value); + void SetUint16(Uint32 Pos,Uint16 Value); + void SetUint8(Uint32 Pos,Uint8 Value); + void SetSint32(Uint32 Pos,Sint32 Value); + void SetSint16(Uint32 Pos,Sint16 Value); + void SetSint8(Uint32 Pos,Sint8 Value); + void SetBit(Uint32 Pos,bool Value); + Uint32 GetUint32(Uint32 Pos); + Uint16 GetUint16(Uint32 Pos); + Uint8 GetUint8(Uint32 Pos); + Sint32 GetSint32(Uint32 Pos); + Sint16 GetSint16(Uint32 Pos); + Sint8 GetSint8(Uint32 Pos); + bool GetBit(Uint32 Pos); + void Clear(); + + // Special operations API + DVector & operator=(const DVector &Src); + bool GetBuffer(Uint8 **Buffer,Uint32 *Length); + bool SetBuffer(Uint8 *Buffer,Uint32 Length); + +}; + +#endif + diff --git a/engines/vileVN/common/edl_common.cpp b/engines/vileVN/common/edl_common.cpp new file mode 100644 index 0000000000..5cba4d07c7 --- /dev/null +++ b/engines/vileVN/common/edl_common.cpp @@ -0,0 +1,335 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "edl_common.h" + +/*! \brief Updates a hash for a byte + * \param Hash Previous hash value + * \param Byte Byte to calculate hash for + * \returns Updated hash value + */ +Uint32 EDL_HashUpdate(Uint32 Hash,Uint8 Byte){ + Uint32 retval=0; +#ifdef VILE_HASH_CCITT16 + // Initialize hash-table on demand + static Uint16 ccitt_table[256]; + static Uint16 ccitt_init=false; + static Uint16 ccitt_poly=0x1021; + if(!ccitt_init){ + for(int i=0;i<256;i++){ + Uint16 tmp=0; + Uint16 c=((Uint16)i<<8); + for(int j=0;j<8;j++){ + if((tmp^c)&0x8000){ + tmp=(tmp<<1)^ccitt_poly; + } + else{ + tmp=tmp<<1; + } + c=c<<1; + } + ccitt_table[i]=tmp; + } + ccitt_init=true; + } + + // Calculate checksum + Uint16 crc=Hash; + Uint16 sc=0x00FF&Byte; + Uint16 tmp=(crc>>8)^sc; + crc=(crc<<8)^ccitt_table[tmp]; + retval=crc; +#endif +#ifdef VILE_HASH_CRC16 + // Initialize hash-table on demand + static Uint16 table[256]; + static Uint16 init=false; + static Uint16 poly=0xA001; + if(!init){ + for(int i=0;i<256;i++){ + Uint16 crc=0; + Uint16 c=(Uint16)i; + for(int j=0;j<8;j++){ + if((crc^c)&0x0001){ + crc=(crc>>1)^poly; + } + else{ + crc=crc>>1; + } + c=c>>1; + } + table[i]=crc; + } + init=true; + } + + // Calculate checksum + Uint16 crc=Hash; + Uint16 sc=0x00FF&Byte; + Uint16 tmp=crc^sc; + crc=(crc>>8)^table[tmp&0xFF]; + retval=crc; +#endif +#ifdef VILE_HASH_CRC32 + // Initialize hash-table on demand + static Uint32 table[256]; + static Uint16 init=false; + static Uint32 poly=0xEDB88320L; + if(!init){ + for(int i=0;i<256;i++){ + Uint32 crc=(Uint32)i; + for(int j=0;j<8;j++){ + if(crc&0x00000001L){ + crc=(crc>>1)^poly; + } + else{ + crc=crc>>1; + } + } + table[i]=crc; + } + init=true; + } + + // Calculate checksum + Uint32 crc=Hash; + Uint32 lc=0x00FF&Byte; + Uint32 tmp=crc^lc; + crc=(crc>>8)^table[tmp&0xFF]; + retval=crc; +#endif + return retval; + +} + +/*! \brief Updates a hash for the pointer to an object + * \param Hash Previous hash value + * \param Pointer Pointer to hash + * \returns Updated hash value + */ +Uint32 EDL_HashUpdate(Uint32 Hash,void *Pointer){ + Uint32 retval=Hash; + retval=EDL_HashUpdate(retval,((Uint32)Pointer>>24)&0xFF); + retval=EDL_HashUpdate(retval,((Uint32)Pointer>>16)&0xFF); + retval=EDL_HashUpdate(retval,((Uint32)Pointer>>8)&0xFF); + retval=EDL_HashUpdate(retval,(Uint32)Pointer&0xFF); + return retval; +} + +/*! \brief Calculates a hash for a string + * \param Text String object + * \returns Hash of the input string + */ +Uint32 EDL_HashString(uString Text){ + return EDL_HashBuffer((Uint8*)Text.c_str(),Text.length()); +} + +/*! \brief Calculates a hash for a byte-buffer + * \param Buffer Pointer to bytes + * \param Length Size of the buffer + * \returns Hash of the input + */ +Uint32 EDL_HashBuffer(Uint8 *Buffer,Uint32 Length){ + Uint32 retval=0; + for(Uint32 i=0;iR2.x+R2.w){ + R2.w=(R1.x+R1.w)-R2.x; + } + if(R1.y+R1.h>R2.y+R2.h){ + R2.h=(R1.y+R1.h)-R2.y; + } + */ + + // Check R2 + if(R2.xR1.x+R1.w){ + R1.w=(R2.x+R2.w)-R1.x; + } + if(R2.y+R2.h>R1.y+R1.h){ + R1.h=(R2.y+R2.h)-R1.y; + } + return R1; +} + + diff --git a/engines/vileVN/common/edl_common.h b/engines/vileVN/common/edl_common.h new file mode 100644 index 0000000000..4485491c47 --- /dev/null +++ b/engines/vileVN/common/edl_common.h @@ -0,0 +1,69 @@ +/*! \unit Common Extended Directmedia Layer + * + * EDL is a ViLE-specific extension of SDL. EDL_Common handles common tasks + * such as text manipulation, random number generation and time handling. It + * also defines basic macros for math, windows and setting structures. + */ + +#ifndef _EDL_COMMON_H_ +#define _EDL_COMMON_H_ + +#ifdef VILE_ARCH_MICROSOFT +#include +#endif +#include +#include +#include +#include "log.h" +#include "cfg.h" + +// Select ONE hash function +#define VILE_HASH_CCITT16 +//#define VILE_HASH_CRC16 +//#define VILE_HASH_CRC32 + +// Basic macros +#define EDL_ODD(A) ((A)%2) +#define EDL_EVEN(A) (!EDL_ODD(A)) +#define EDL_ABS(A) (A<0?A*-1:A) +#define EDL_MAX(A,B) (B>A?B:A) +#define EDL_MIN(A,B) (B=0){ + mask=tmp.substr(0,lastsep+1); + } + mask+="*"; + wordexp_t p; + if(wordexp(mask.c_str(),&p,0)==0){ + for(unsigned int i=0;i0;i--){ + if(Filemask[i-1]=='/' || Filemask[i-1]=='\\'){ + break; + } + } + if(i>0){ + folder=Filemask.substr(0,i); + } + + // Search for files matching input mask + WIN32_FIND_DATA FindFileData; + HANDLE findhandle=FindFirstFile(Filemask.c_str(),&FindFileData); + if(findhandle!=INVALID_HANDLE_VALUE){ + // Handle first file + bool run=true; + while(run){ + // Handle found file + uString filename=FindFileData.cFileName; + if(filename!="." && filename!=".."){ + retval.AddString(folder+filename); + } + + // Get next file + run=FindNextFile(findhandle,&FindFileData); + } + + // Close search + FindClose(findhandle); + } +#elif VILE_ARCH_NDS +//#error "File enumeration not supported" +#else +#error "File enumeration not supported" +#endif + return retval; +} + +/*! \brief Gets proper casing of filenames on a unixsystem + * \param Path Input path (Will not be checked) + * \param Filename Input filename (Might be a directory) + * \return Pathname with correct casing + * + * This method finds casing of a filename in a case sensitive path + */ +uString EDL_Realname(uString Path,uString Filename){ +#if HAVE_WORDEXP_H + // Escape spaces in input string + uString mask; + for(unsigned int i=0;i=0){ + pathname=pathname.substr(lastsep+1); + } + + // Check if input file matches + if(pathname==Filename){ + Filename=p.we_wordv[k]; + if(lastsep>=0){ + Filename=Filename.substr(lastsep+1); + } + break; + } + } + wordfree(&p); + } +#elif VILE_ARCH_MICROSOFT + // Casing is already ignored under windwoes +#elif VILE_ARCH_NDS +//#error "File case-ignoring not supported" +#else +#error "File case-ignoring not supported" +#endif + return Path+Filename; +} + +/*! \brief Gets proper casing of filenames on a unixsystem + * \param Filename Input filename + * \return Pathname with correct casing + * + * Since these games stems from windows they do not not have a convention + * or standard on the casing of the resource files. This function takes the + * suggested pathname and checks it for real files in the filesystem. + */ +uString EDL_Realname(uString Filename){ +#ifdef VILE_ARCH_MICROSOFT + // Dont bother with real name on a case insensitive system + return Filename; +#else + // Check if input already comply + struct stat ss; + if(stat(Filename.c_str(),&ss)==0){ + if((ss.st_mode&S_IFMT)==S_IFDIR && Filename[Filename.length()-1]!='/'){ + Filename+="/"; + } + return Filename; + } + + // Resolve nested path + uString relative; + for(unsigned int i=0;i0){ + Filename=Filename.substr(0,dpos); + } + if(spos>0){ + Filename=Filename.substr(spos+1); + } + return Filename; +} + +/*! \brief Strips quotes and simular fuzz from a commandline path + * \param Path Input path + * \return Stripped version of Path + */ +uString EDL_StripPath(uString Path){ + // Strip quotes + while(Path.length() && Path[0]=='"'){ + Path=Path.substr(1,Path.length()-1); + } + while(Path.length() && Path[Path.length()-1]=='"'){ + Path=Path.substr(0,Path.length()-1); + } + Path=EDL_Realname(Path); + return Path; +} + +/*! \brief Gets one and one file from the specified path + * \param Pathname Pathname to search + * \param Filename Filename if any + * \return True if a(nother) file could be named + * + * Setting the pathname is key, subsequent calls for the same + * pathname will render a new file file until all files has been + * enumerated. Subsequent calls after a failed call will start over. + */ +bool EDL_GetFile(uString Pathname,uString *Filename){ + bool retval=false; + static uString curpath=""; +#ifdef VILE_ARCH_MICROSOFT + static HANDLE finddir=INVALID_HANDLE_VALUE; + if(finddir==INVALID_HANDLE_VALUE || Pathname!=curpath){ + // Find first file + curpath=Pathname; + uString filemask=Pathname+"*"; + WIN32_FIND_DATA FindFileData; + if(finddir!=INVALID_HANDLE_VALUE){ + FindClose(finddir); + } + finddir=FindFirstFile(filemask.c_str(),&FindFileData); + if(finddir!=INVALID_HANDLE_VALUE){ + *Filename=FindFileData.cFileName; + retval=true; + } + } + else{ + // Find next file + WIN32_FIND_DATA FindFileData; + if(FindNextFile(finddir,&FindFileData)){ + *Filename=FindFileData.cFileName; + retval=true; + } + else{ + FindClose(finddir); + finddir=INVALID_HANDLE_VALUE; + } + } +#else + static DIR *finddir=0; + if(finddir==NULL || Pathname!=curpath){ + if(finddir!=NULL){ + closedir(finddir); + } + curpath=Pathname; + finddir=opendir(curpath.c_str()); + } + if(finddir!=NULL){ + dirent *entry=readdir(finddir); + if(entry){ + *Filename=entry->d_name; + retval=true; + } + else{ + closedir(finddir); + finddir=0; + } + } +#endif + return retval; +} + +/*! \brief Tests wether a given file is readable + * \param Path Path to the believed filename + * \return True if the file was readable + * + * This method will return false if the specified file was a directory. + */ +bool EDL_ReadableFile(uString Path){ +#ifdef VILE_ARCH_MICROSOFT + int test=GetFileAttributes(Path.c_str()); + return (test!=-1 && !(test&FILE_ATTRIBUTE_DIRECTORY)); +#else + struct stat ss; + return (stat(Path.c_str(),&ss)==0 && ((ss.st_mode&S_IFMT)!=S_IFDIR)); +#endif +} + +/*! \brief Tests wether a given file is writable + * \param Path Path to the believed filename + * \return True if the file was writable + * + * This method will return false if the specified file was a directory. + */ +bool EDL_WritableFile(uString Path){ +#ifdef VILE_ARCH_MICROSOFT + int test=GetFileAttributes(Path.c_str()); + return (test!=-1 && + !test&FILE_ATTRIBUTE_DIRECTORY && + !test&FILE_ATTRIBUTE_READONLY); +#else + struct stat ss; + return (stat(Path.c_str(),&ss)==0 && + ((ss.st_mode&S_IFMT)!=S_IFDIR) && + (ss.st_mode&S_IWUSR)); +#endif +} + +/*! \brief Changes the current directory (CWD) + * \param Path New directory path + * \returns True if path was accepted + */ +bool EDL_SetDirectory(uString Path){ +#ifdef HAVE_WORDEXP_H + wordexp_t p; + if(wordexp(Path.c_str(),&p,0)==0){ + Path=p.we_wordv[0]; + wordfree(&p); + } + return (chdir(Path.c_str())==0); +#else + return (chdir(Path.c_str())==0); +#endif +} + +/*! \brief Creates a new directory (duh!) + * \param Path Path of new directory + * \returns True if directory was successfully created + */ +bool EDL_CreateDirectory(uString Path){ +#ifdef HAVE_WORDEXP_H + // Expand path before changing path + wordexp_t p; + if(wordexp(Path.c_str(),&p,0)==0){ + Path=p.we_wordv[0]; + wordfree(&p); + } + return (mkdir(Path.c_str(),0777)==0); +#elif VILE_ARCH_MICROSOFT + return (mkdir(Path.c_str())==0); +#else + return (mkdir(Path.c_str(),0777)==0); +#endif +} + +/*! \brief Tests wether a given directory is readable + * \param Path Path to the believed directory + * \return True if the directory was readable + * + * This method will return false if the specified directory was a file. + */ +bool EDL_ReadableDirectory(uString Path){ + struct stat ss; + return (stat(Path.c_str(),&ss)==0 && ((ss.st_mode&S_IFMT)==S_IFDIR)); +} + +/*! \brief Tests wether a given directory is writable + * \param Path Path to the believed directory + * \return True if the directory was writeable + * + * This method will return false if the specified directory was a file. + */ +bool EDL_WritableDirectory(uString Path){ + struct stat ss; + return (stat(Path.c_str(),&ss)==0 && + ((ss.st_mode&S_IFMT)==S_IFDIR) && + (ss.st_mode&S_IWUSR)); +} + +/*! \brief Deletes a file from the filesystem + * \param Path Path to the file to delete + * \return True if the file was deleted + */ +bool EDL_DeleteFile(uString Path){ + return (unlink(Path.c_str())==0); +} + +/*! \brief Deletes a directory from the filesystem + * \param Path Path to the directory to delete + * \return True if the directory was deleted + */ +bool EDL_DeleteDirectory(uString Directory){ + bool retval=false; +#ifdef VILE_ARCH_MICROSOFT + // "Double nullterminate" pathname + char path_from[Directory.length()+2]; + strncpy(path_from,Directory.c_str(),Directory.length()); + path_from[Directory.length()]=0; + path_from[Directory.length()+1]=0; + + // Use Windows API to remove the file + SHFILEOPSTRUCT fileop; + fileop.hwnd=NULL; + fileop.wFunc=FO_DELETE; + fileop.pFrom=path_from; + fileop.pTo=NULL; + fileop.fFlags=FOF_NOCONFIRMATION | FOF_SILENT; + fileop.fAnyOperationsAborted=FALSE; + fileop.lpszProgressTitle=NULL; + fileop.hNameMappings=NULL; + retval=(SHFileOperation(&fileop)==0); +#elif VILE_ARCH_NDS +#warning Directory deletion not supported under Nintendo DS +#else + // Assert trailing separator and traverse directory + if(Directory[Directory.length()-1]!='\\'){ + Directory+="/"; + } + struct dirent *pent=NULL; + DIR *pdir=opendir(Directory.c_str()); + while(pdir && (pent=readdir(pdir))){ + if(pent==0){ + // Ooops + break; + } + if(!strcmp(pent->d_name,".")){ + // Ignore dots + } + else if(!strcmp(pent->d_name,"..")){ + // Ignore dots + } + else{ + // Recursively delete item + uString file=Directory+pent->d_name; + if(EDL_WritableDirectory(file)){ + EDL_DeleteDirectory(file); + } + else{ + EDL_DeleteFile(file); + } + } + } + + // Close traverser and actually delete directory + closedir(pdir); + retval=(rmdir(Directory.c_str())==0); +#endif + return retval; +} + +/*! \brief Creates an uniquely named temporary directory + * \return Path to new temporary directory + * + * Remember to delete the temporary directory after use! + */ +uString EDL_CreateTemporary(){ + uString retval; +#ifdef VILE_ARCH_MICROSOFT + TCHAR lpPathBuffer[MAX_PATH]; + DWORD dwRetVal=GetTempPath(MAX_PATH,lpPathBuffer); + if(dwRetVal<=MAX_PATH) + { + // Shift directory to string and get unique filename + uString path=lpPathBuffer; + if(GetTempFileName(path.c_str(),"ViLEVN",0,lpPathBuffer)!=0){ + // Create directory + EDL_DeleteFile(lpPathBuffer); + if(CreateDirectory(lpPathBuffer,0)!=0){ + retval=lpPathBuffer; + } + } + } +#else + uString tmps="/var/tmp/"; + if(!EDL_WritableDirectory(tmps)){ + tmps="/tmp/"; + if(!EDL_WritableDirectory(tmps)){ + tmps=""; + } + } + tmps+="ViLE-XXXXXX"; + char tmpc[tmps.length()]; + strcpy(tmpc,tmps.c_str()); + retval=mkdtemp(tmpc); + if(retval.length()){ + retval+="/"; + } +#endif + return retval; +} + +/*! \brief Parses the directory name from a path + * \param Path Path with directory and filename + * \return Path with filename and extension stripped off + */ +uString EDL_FileDirectory(uString Path){ + uString retval; + if(EDL_ReadableDirectory(Path)){ + // Given path is already a directory + retval=Path; + if(Path[Path.length()-1]!='/' && Path[Path.length()-1]!='\\'){ + retval+="/"; + } + } + else{ + // Parse last separator + for(int i=Path.length()-1;i>=0;i--){ + if(Path[i]=='/' || Path[i]=='\\'){ + retval=Path.substr(0,i+1); + break; + } + } + } + return retval; +} + +/*! \brief Parses the basename from a path (Without extension) + * \param Path Path with optional directory and/or extension + * \return Path with directory and extension stripped off + */ +uString EDL_FileName(uString Path){ + uString dirname=EDL_FileDirectory(Path); + uString extname=EDL_FileExtension(Path); + uString filename=Path.substr(dirname.length()); + if(extname.length()){ + // Drop extension + filename=filename.substr(0,filename.length()-(extname.length()+1)); + } + else if(filename.length()){ + // Drop trailing dot + if(filename[filename.length()-1]=='.'){ + return filename.substr(0,filename.length()-1); + } + } + return filename; +} + +/*! \brief Strips directory and basename from the given path + * \param Path Path to be stripped + * \return File extension (Without leading dot) + */ +uString EDL_FileExtension(uString Path){ + // Parse last separator + uString retval; + for(int i=Path.length()-1;i>=0;i--){ + if(Path[i]=='/' || Path[i]=='\\'){ + break; + } + if(Path[i]=='.'){ + retval=Path.substr(i+1); + break; + } + } + return retval; +} + +/*! \brief Enforces a new extension even if path already has one + * \param Path Filename with optional directory + * \param Extension New extension + * \return Path with new extension + */ +uString EDL_ForceExtension(uString Path,uString Extension){ + if(Path.length()){ + for(unsigned int i=Path.length();i>0;i--){ + if(Path[i-1]=='.'){ + // Change existing extension + Path=Path.substr(0,i-1); + if(Path[Path.length()-1]!='.' && Extension[0]!='.'){ + Path+="."; + } + Path+=Extension; + break; + } + if(Path[i-1]=='/' || Path[i-1]=='\\'){ + if(i==Path.length()){ + // Append extension + if(Path[Path.length()-1]!='.' && Extension[0]!='.'){ + Path+="."; + } + Path+=Extension; + } + break; + } + } + uString oldext=EDL_FileExtension(Path); + if(oldext==""){ + if(Path[Path.length()-1]!='.' && Extension[0]!='.'){ + Path+="."; + } + Path+=Extension; + } + } + return Path; +} + +/*! \brief Sets extension if none is previously set + * \param Filename with optional directory + * \param Extension New extension + * \return Path with asserted extension + */ +uString EDL_DefaultExtension(uString Path,uString Extension){ + if(Path.length() && Extension.length()){ + uString oldext=EDL_FileExtension(Path); + if(oldext==""){ + if(Path[Path.length()-1]!='.' && Extension[0]!='.'){ + Path+="."; + } + Path+=Extension; + } + } + return Path; +} + diff --git a/engines/vileVN/common/edl_fs.h b/engines/vileVN/common/edl_fs.h new file mode 100644 index 0000000000..2750caf6ea --- /dev/null +++ b/engines/vileVN/common/edl_fs.h @@ -0,0 +1,57 @@ +/*! \unit File system extensions to SDL + * \todo Implement UNICODE compliant filesystem integration + * + * EDL is a ViLE-specific extension of SDL. EDL_FS handles filesystem tasks + * in a portable manner, and allows ViLE to check read/write permissions, + * get the correct casing of a path, etc. + */ + +#ifndef _EDL_FS_H_ +#define _EDL_FS_H_ + +#include "edl_common.h" +#include "stringlist.h" +#ifdef VILE_ARCH_MICROSOFT +#include +#include +#include +#include +#include +#else +#include +#include +#endif +#include +#ifdef HAVE_WORDEXP_H +#include +#include +#endif + + +// ----- Filename utilities ----- +extern uString EDL_StripPath(uString Path); +extern uString EDL_Searchname(uString Filename); +extern uString EDL_FileDirectory(uString Path); +extern uString EDL_FileName(uString Path); +extern uString EDL_FileExtension(uString Path); +extern uString EDL_ForceExtension(uString Path,uString Extension); +extern uString EDL_DefaultExtension(uString Path,uString Extension); + + +// ----- File utilities ----- +extern bool EDL_SetDirectory(uString Path); +extern bool EDL_ReadableDirectory(uString Path); +extern bool EDL_ReadableFile(uString Path); +extern bool EDL_WritableDirectory(uString Path); +extern bool EDL_WritableFile(uString Path); +extern bool EDL_CreateDirectory(uString Path); +extern bool EDL_DeleteDirectory(uString Path); +extern bool EDL_DeleteFile(uString Path); +extern bool EDL_GetFile(uString Pathname,uString *Filename); +extern uString EDL_CreateTemporary(); +extern uString EDL_Realname(uString Filename); +extern Stringlist EDL_Expandname(uString Filename); + + +#endif + diff --git a/engines/vileVN/common/edl_gfx.cpp b/engines/vileVN/common/edl_gfx.cpp new file mode 100644 index 0000000000..5b2e5e59da --- /dev/null +++ b/engines/vileVN/common/edl_gfx.cpp @@ -0,0 +1,957 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "edl_gfx.h" + +inline void EDL_GetPixel_8bit(SDL_Surface * surface, + Sint16 x,Sint16 y, + Uint8 *red,Uint8 *green,Uint8 *blue,Uint8 *alpha){ + Uint8 *pixel=(Uint8*)surface->pixels+y*surface->pitch+x; + *red=surface->format->palette->colors[*pixel].r; + *green=surface->format->palette->colors[*pixel].g; + *blue=surface->format->palette->colors[*pixel].b; + *alpha=0xFF; +} + +inline void EDL_SetPixel_8bit(SDL_Surface * surface, + Sint16 x,Sint16 y,Uint8 red,Uint8 green,Uint8 blue,Uint8 alpha){ + Uint8 *pixel=(Uint8*)surface->pixels+y*surface->pitch+x; + *pixel=SDL_MapRGB(surface->format,red,green,blue); +} + +inline void EDL_GetPixel_16bit(SDL_Surface *surface, + Sint16 x,Sint16 y, + Uint8 *red,Uint8 *green,Uint8 *blue,Uint8 *alpha){ + Uint8 *pixel=(Uint8*)surface->pixels+y*surface->pitch+x; + Uint32 dc=*pixel; + *red=(dc&surface->format->Rmask)>>surface->format->Rshift; + *green=(dc&surface->format->Gmask)>>surface->format->Gshift; + *blue=(dc&surface->format->Bmask)>>surface->format->Bshift; + if(surface->format->Amask){ + *alpha=(dc&surface->format->Amask)>>surface->format->Ashift; + } + else{ + *alpha=0xFF; + } +} + +inline void EDL_SetPixel_16bit(SDL_Surface * surface, + Sint16 x,Sint16 y,Uint8 red,Uint8 green,Uint8 blue,Uint8 alpha){ + Uint32 color=0; + color|=(red<format->Rshift)&surface->format->Rmask; + color|=(green<format->Gshift)&surface->format->Gmask; + color|=(blue<format->Bshift)&surface->format->Bmask; + color|=(alpha<format->Ashift)&surface->format->Amask; + *((Uint16*)surface->pixels+y*surface->pitch/2+x)=color; +} + +inline void EDL_GetPixel_24bit(SDL_Surface *surface, + Sint16 x,Sint16 y, + Uint8 *red,Uint8 *green,Uint8 *blue,Uint8 *alpha){ + Uint8 *pix=(Uint8*)surface->pixels+y*surface->pitch+x*3; + Uint8 rshift8=surface->format->Rshift/8; + Uint8 gshift8=surface->format->Gshift/8; + Uint8 bshift8=surface->format->Bshift/8; + Uint8 ashift8=surface->format->Ashift/8; + *red=*((pix)+rshift8); + *green=*((pix)+gshift8); + *blue=*((pix)+bshift8); + if(surface->format->Amask){ + *alpha=*((pix)+ashift8); + } + else{ + *alpha=0xFF; + } +} + +inline void EDL_SetPixel_24bit(SDL_Surface * surface, + Sint16 x,Sint16 y,Uint8 red,Uint8 green,Uint8 blue,Uint8 alpha){ + Uint8 *pix=(Uint8*)surface->pixels+y*surface->pitch+x*3; + Uint32 color=blue<<16|green<<8|red; + Uint8 rshift8=surface->format->Rshift/8; + Uint8 gshift8=surface->format->Gshift/8; + Uint8 bshift8=surface->format->Bshift/8; + Uint8 ashift8=surface->format->Ashift/8; + *(pix + rshift8) = color >> surface->format->Rshift; + *(pix + gshift8) = color >> surface->format->Gshift; + *(pix + bshift8) = color >> surface->format->Bshift; + if(surface->format->Amask){ + *(pix + ashift8) = color >> surface->format->Ashift; + } +} + +inline void EDL_GetPixel_32bit(SDL_Surface *surface, + Sint16 x,Sint16 y, + Uint8 *red,Uint8 *green,Uint8 *blue,Uint8 *alpha){ + Uint32 *pixel=(Uint32*)surface->pixels+y*surface->pitch/4+x; + *red=((*pixel)&surface->format->Rmask)>>surface->format->Rshift; + *green=((*pixel)&surface->format->Gmask)>>surface->format->Gshift; + *blue=((*pixel)&surface->format->Bmask)>>surface->format->Bshift; + if(surface->format->Amask){ + *alpha=((*pixel)&surface->format->Amask)>>surface->format->Ashift; + } + else{ + *alpha=0xFF; + } +} + +inline void EDL_SetPixel_32bit(SDL_Surface * surface, + Sint16 x,Sint16 y,Uint8 red,Uint8 green,Uint8 blue,Uint8 alpha){ + Uint32 *pixel=(Uint32*)surface->pixels+y*surface->pitch/4+x; + Uint32 R=(red<format->Rshift)&surface->format->Rmask; + Uint32 G=(green<format->Gshift)&surface->format->Gmask; + Uint32 B=(blue<format->Bshift)&surface->format->Bmask; + Uint32 A=(alpha<format->Ashift)&surface->format->Amask; + *pixel=R|G|B|A; +} + +inline void EDL_GetPixel_auto(SDL_Surface *surface, + Sint16 x,Sint16 y, + Uint8 *red,Uint8 *green,Uint8 *blue,Uint8 *alpha){ + switch (surface->format->BytesPerPixel) { + case 1: EDL_GetPixel_8bit(surface,x,y,red,green,blue,alpha); break; + case 2: EDL_GetPixel_16bit(surface,x,y,red,green,blue,alpha); break; + case 3: EDL_GetPixel_24bit(surface,x,y,red,green,blue,alpha); break; + case 4: EDL_GetPixel_32bit(surface,x,y,red,green,blue,alpha); break; + } +} + +inline void EDL_SetPixel_auto(SDL_Surface * surface, + Sint16 x,Sint16 y,Uint8 red,Uint8 green,Uint8 blue,Uint8 alpha){ + switch (surface->format->BytesPerPixel) { + case 1: EDL_SetPixel_8bit(surface,x,y,red,green,blue,alpha); break; + case 2: EDL_SetPixel_16bit(surface,x,y,red,green,blue,alpha); break; + case 3: EDL_SetPixel_24bit(surface,x,y,red,green,blue,alpha); break; + case 4: EDL_SetPixel_32bit(surface,x,y,red,green,blue,alpha); break; + } +} + +/*! \brief Reads and maps a given pixel + * \param Surface Source surface + * \param X Source coordinate + * \param Y Source coordinate + * \param Red Pointer to receive red color value + * \param Green Pointer to receive green color value + * \param Blue Pointer to receive blue color value + * \param Alpha Pointer to receive alpha channel value + */ +void EDL_GetPixel(SDL_Surface *Surface, + Sint16 X,Sint16 Y, + Uint8 *Red,Uint8 *Green,Uint8 *Blue,Uint8 *Alpha){ + // Lock source + if(SDL_MUSTLOCK(Surface)){ + if(SDL_LockSurface(Surface)<0){ + return; + } + } + + // Read pixel + EDL_GetPixel_auto(Surface,X,Y,Red,Green,Blue,Alpha); + + // Unlock + if(SDL_MUSTLOCK(Surface)){ + SDL_UnlockSurface(Surface); + } +} + +/*! \brief Reads and maps rgba value of a given pixel + * \param Surface Source surface + * \param X Source coordinate + * \param Y Source coordinate + * \return Colorvalue of given pixel (0 if failed) + */ +Uint32 EDL_GetPixel(SDL_Surface *surface,Sint16 x,Sint16 y){ + Uint32 retval=0; + if(surface){ + Uint8 r,g,b,a; + EDL_GetPixel(surface,x,y,&r,&g,&b,&a); + retval=(r<<24)|(g<<16)|(b<<8)|a; + } + return retval; +} + +/*! \brief Reads and maps a given pixel + * \param Surface Source surface + * \param X Source coordinate + * \param Y Source coordinate + * \param Red Pointer to receive red color value + * \param Green Pointer to receive green color value + * \param Blue Pointer to receive blue color value + * \param Alpha Pointer to receive alpha channel value + */ +void EDL_SetPixel(SDL_Surface *Surface, + Sint16 X,Sint16 Y, + Uint8 Red,Uint8 Green,Uint8 Blue,Uint8 Alpha){ + // Lock source + if(SDL_MUSTLOCK(Surface)){ + if(SDL_LockSurface(Surface)<0){ + return; + } + } + + // Read pixel + EDL_SetPixel_auto(Surface,X,Y,Red,Green,Blue,Alpha); + + // Unlock + if(SDL_MUSTLOCK(Surface)){ + SDL_UnlockSurface(Surface); + } +} + +/*! \brief Saves a surface to specified file + * \param surface Surface to save + * \param Filename Filename to save as (A three digit number will be appended) + */ +void EDL_SaveSurface(SDL_Surface *surface,uString File){ + bool done=false; + int cnt=0; + while(!done){ + char fname[255]; + sprintf(fname,"%s-%03d.bmp",File.c_str(),cnt++); + FILE *tf=fopen(fname,"rb"); + if(!tf){ + tf=fopen(fname,"wb"); + if(tf){ + done=true; + fclose(tf); + SDL_SaveBMP(surface,fname); + } + } + else{ + fclose(tf); + } + } +} + +/*! \brief Creates a new surface with alpha channel + * \param Width Width of new surface + * \param Height Height of new surface + * \returns New surface + */ +SDL_Surface *EDL_CreateSurface(int Width,int Height){ + if(Width>0 && Height>0){ + return SDL_CreateRGBSurface(SDL_SWSURFACE|SDL_SRCALPHA,Width,Height,32, +#if SDL_BYTEORDER == SDL_BIG_ENDIAN + 0xff000000,0x00ff0000,0x0000ff00,0x000000ff); +#else + 0x000000ff,0x0000ff00,0x00ff0000,0xff000000); +#endif + } + else{ + return 0; + } +} + +/*! \brief Generates and blits a text surface (Including alpha layer) + * \param Text String to render + * \param Color Color to render text in + * \param dst Destination surface + * \param dstrect Destination rectangle + * + * Text size will be automatically fitted for the destination rectangle + */ +void EDL_BlitText(uString Text,Uint32 Color, + SDL_Surface *dst,SDL_Rect *dstrect){ + SDL_Rect drect={0,0,dst->w,dst->h}; + if(dstrect){ + drect=*dstrect; + } + SDL_Surface *tmp=EDL_CreateText(Text,Color,drect.w,drect.h); + if(tmp){ + EDL_BlitSurface(tmp,0,dst,&drect); + SDL_FreeSurface(tmp); + } +} + +/*! \brief Renders a text string and blends it into a surface + * \param Text String to render + * \param Color Color to render text in + * \param dst Destination surface + * \param dstrect Destination surface + * + * Text size will be automatically fitted for the destination rectangle + */ +void EDL_BlendText(uString Text,Uint32 Color, + SDL_Surface *dst,SDL_Rect *dstrect){ + SDL_Rect drect={0,0,dst->w,dst->h}; + if(dstrect){ + drect=*dstrect; + } + SDL_Surface *tmp=EDL_CreateText(Text,Color,drect.w,drect.h); + if(tmp){ + EDL_BlendSurface(tmp,0,dst,&drect); + SDL_FreeSurface(tmp); + } +} + +/*! \brief Calculates size of a given text + * \param Text String to calculate + * \param Size Font size (more or less the same as the height) + * \param Width Pointer to width variable + * \param Height Pointer to height variable + * \returns True if string can be rendered + */ +bool EDL_SizeText(uString Text,int Size,int *Width,int *Height){ + bool retval=false; + if(Text.length()){ + uString face=Cfg::Font::default_face; + TTF_Font *font=TTF_OpenFont(face.c_str(),Size); + if(font){ + if(!TTF_SizeText(font,Text.c_str(),Width,Height)){ + retval=true; + } + TTF_CloseFont(font); + } + } + return retval; +} + +/*! \brief Creates a surface with a text that spans multiple lines + * \param Text String to render (Newlines indicates linebreak) + * \param Color Font color + * \param Width Width of the resulting surface + * \param Height Height of the resulting surface + * \return Surface with rendered text + */ +SDL_Surface *EDL_CreateMultilineText(uString Text, + Uint32 Color,int Width,int Height){ + SDL_Surface *retval=EDL_CreateSurface(Width,Height); + unsigned int h=Cfg::Font::default_size; + unsigned int s=0; + unsigned int e=0; + unsigned int i=0; + for(;es){ + uString t=Text.substr(s,e-s); + SDL_Surface *tmp=EDL_CreateText(t,Color,Width,h); + SDL_Rect tr={0,h*i++,Width,h}; + EDL_BlitSurface(tmp,0,retval,&tr); + SDL_FreeSurface(tmp); + } + s=e+1; + } + } + if(e>s){ + uString t=Text.substr(s,e-s); + SDL_Surface *tmp=EDL_CreateText(t,Color,Width,h); + SDL_Rect tr={0,h*i++,Width,h}; + EDL_BlitSurface(tmp,0,retval,&tr); + SDL_FreeSurface(tmp); + } + return retval; +} + +/*! \brief Creates a blendable text and automatically sizes it + * \param Text Text to render + * \param Color Color to render the text in + * \param Width Width of result surface + * \param Height Height of result surface + * \return blendable surface with text rendered on it + */ +SDL_Surface *EDL_CreateText(uString Text, + Uint32 Color,int Width,int Height){ + // Create and configure a font object + SDL_Surface *retval=0; + uString face=Cfg::Font::default_face; + int size=Cfg::Font::default_size; + FILE *tf=fopen(face.c_str(),"rb"); + if(!tf){ + LogError("Failed to find font: %s",face.c_str()); + } + else{ + fclose(tf); + } + if(tf && size>0 && Text.length()){ + // Load font and poll for size + int tw,th; + TTF_Font *font=0; + for(int i=4;iWidth || th>Height){ + TTF_CloseFont(font); + break; + } + else{ + size=i; + } + } + TTF_CloseFont(font); + } + font=TTF_OpenFont(face.c_str(),size); + if(font){ + SDL_Color color={(Color>>24)&0xFF,(Color>>16)&0xFF,Color>>8}; + retval=EDL_RenderText(font,Text,color); + TTF_CloseFont(font); + } + } + return retval; +} + +SDL_Surface *EDL_RenderText(TTF_Font *Font,const uString &Text,SDL_Color fg){ +#if VILE_BUILD_UNICODE + return TTF_RenderUTF8_Blended(Font,Text.c_str(),fg); +#else + return TTF_RenderText_Blended(Font,Text.c_str(),fg); +#endif +} + +/*! \brief Alphablends a bitmap onto a new surface using a colorkey + * \param Bitmap Source surface + * \param Rect Source rectangle and destination size + * \returns New SDL_Surface with alphachannel as graphics + * + * This lumpy thing autodetects a colorkey from the four corners. + */ +SDL_Surface *EDL_ColorkeySurface(SDL_Surface *Bitmap,SDL_Rect *Rect){ + // Autodetect colorkey + Uint32 c1=EDL_GetPixel(Bitmap,0,0); + Uint32 c2=EDL_GetPixel(Bitmap,Bitmap->w-1,0); + Uint32 c3=EDL_GetPixel(Bitmap,0,Bitmap->h-1); + Uint32 c4=EDL_GetPixel(Bitmap,Bitmap->w-1,Bitmap->h-1); + int m1=0; + int m2=0; + int m3=0; + int m4=0; + if(c1==c2){ + m1++; + m2++; + } + if(c1==c3){ + m1++; + m3++; + } + if(c1==c4){ + m1++; + m4++; + } + if(c2==c3){ + m2++; + m3++; + } + if(c2==c4){ + m2++; + m4++; + } + if(c3==c4){ + m2++; + m3++; + } + + if(m1>2){ + return EDL_ColorkeySurface(Bitmap,c1,Rect); + } + if(m2>2){ + return EDL_ColorkeySurface(Bitmap,c2,Rect); + } + if(m3>2){ + return EDL_ColorkeySurface(Bitmap,c3,Rect); + } + if(m4>2){ + return EDL_ColorkeySurface(Bitmap,c4,Rect); + } + if(m1>1){ + return EDL_ColorkeySurface(Bitmap,c1,Rect); + } + if(m2>1){ + return EDL_ColorkeySurface(Bitmap,c2,Rect); + } + if(m3>1){ + return EDL_ColorkeySurface(Bitmap,c3,Rect); + } + if(m4>1){ + return EDL_ColorkeySurface(Bitmap,c4,Rect); + } + return EDL_ColorkeySurface(Bitmap,c1,Rect); +} + +/*! \brief Alphablends a bitmap onto a new surface using a colorkey + * \param Bitmap Source surface + * \param Key Color to filter + * \param Rect Source rectangle and destination size + * \returns New SDL_Surface with alphachannel as graphics + */ +SDL_Surface *EDL_ColorkeySurface(SDL_Surface *Bitmap, + Uint32 Key,SDL_Rect *Rect){ + SDL_Surface *retval=0; + if(Bitmap){ + // Get target rect + SDL_Rect rect={0,0,Bitmap->w,Bitmap->h}; + if(Rect){ + if(Rect->xx; + if(Rect->yy; + if(Rect->ww; + if(Rect->hh; + } + + // Create destination + retval=EDL_CreateSurface(rect.w,rect.h); + + // Lock surfaces + if(SDL_MUSTLOCK(Bitmap)){ + if(SDL_LockSurface(Bitmap)<0){ + return 0; + } + } + if(SDL_MUSTLOCK(retval)){ + if(SDL_LockSurface(retval)<0){ + return 0; + } + } + + // Map alpha channel by colorkey + for(int y=0;y>24)&0xFF,kg=(Key>>16)&0xFF,kb=(Key>>8)&0xFF; + Uint8 br=0,bg=0,bb=0,ba=0xFF; + int dx=x+rect.x; + int dy=y+rect.y; + if(dx>=0 && dy>=0){ + if(dx<=Bitmap->w && dy<=Bitmap->h){ + EDL_GetPixel_auto(Bitmap, + x+rect.x,y+rect.y, + &br,&bg,&bb,&ba); + if(br==kr && bg==kg && bb==kb){ + ba=0; + } + else{ + ba=0xFF; + } + } + EDL_SetPixel_auto(retval,x,y,br,bg,bb,ba); + } + } + } + + // Unlock + if(SDL_MUSTLOCK(Bitmap)){ + SDL_UnlockSurface(Bitmap); + } + if(SDL_MUSTLOCK(retval)){ + SDL_UnlockSurface(retval); + } + } + return retval; +} + +/*! \brief Alphablends a bitmap onto a new surface using a b/w mask + * \param Bitmap Source surface + * \param Mask Mask surface + * \param Rect Source rectangle and destination size + * \returns New SDL_Surface with alphachannel as graphics + */ +SDL_Surface *EDL_MaskSurface(SDL_Surface *Bitmap, + SDL_Surface *Mask,SDL_Rect *Rect){ + SDL_Surface *retval=0; + if(Bitmap){ + // Get target rect + SDL_Rect rect={0,0,Bitmap->w,Bitmap->h}; + if(Rect){ + if(Rect->xx; + if(Rect->yy; + if(Rect->ww; + if(Rect->hh; + } + + // Create destination + retval=EDL_CreateSurface(rect.w,rect.h); + + // Lock surfaces + if(SDL_MUSTLOCK(Bitmap)){ + if(SDL_LockSurface(Bitmap)<0){ + return 0; + } + } + if(SDL_MUSTLOCK(Mask)){ + if(SDL_LockSurface(Mask)<0){ + return 0; + } + } + if(SDL_MUSTLOCK(retval)){ + if(SDL_LockSurface(retval)<0){ + return 0; + } + } + + // Map alpha channel + for(int y=0;y=0 && dy>=0){ + if(dx<=Bitmap->w && dy<=Bitmap->h){ + EDL_GetPixel_auto(Bitmap, + x+rect.x,y+rect.y, + &br,&bg,&bb,&ba); + } + if(dx<=Mask->w && dy<=Mask->h){ + EDL_GetPixel_auto(Mask, + x+rect.x,y+rect.y, + &mr,&mg,&mb,&ma); + } + EDL_SetPixel_auto(retval,x,y,br,bg,bb,(mr+mg+mb)/3); + } + } + } + + // Unlock + if(SDL_MUSTLOCK(Bitmap)){ + SDL_UnlockSurface(Bitmap); + } + if(SDL_MUSTLOCK(Mask)){ + SDL_UnlockSurface(Mask); + } + if(SDL_MUSTLOCK(retval)){ + SDL_UnlockSurface(retval); + } + } + return retval; + +} + +/*! \brief Maps the alpha channel of a surface onto a new one + * \param Source Source surface + * \param Rect Source rectangle and destination size + * \returns New SDL_Surface with alphachannel as graphics + */ +SDL_Surface *EDL_MapSurface(SDL_Surface *Source,SDL_Rect *Rect){ + SDL_Surface *retval=0; + if(Source && Source->format->Amask){ + // Get target rect + SDL_Rect rect={0,0,Source->w,Source->h}; + if(Rect){ + if(Rect->xx; + if(Rect->yy; + if(Rect->ww; + if(Rect->hh; + } + + // Create destination + retval=EDL_CreateSurface(rect.w,rect.h); + + // Lock surfaces + if(SDL_MUSTLOCK(Source)){ + if(SDL_LockSurface(Source)<0){ + return 0; + } + } + if(SDL_MUSTLOCK(retval)){ + if(SDL_LockSurface(retval)<0){ + return 0; + } + } + + // Map alpha channel + for(int y=0;yw && dx>=0 && dy<=Source->h && dy>=0){ + EDL_GetPixel_auto(Source,x+rect.x,y+rect.y,&r,&g,&b,&a); + } + EDL_SetPixel_auto(retval,x,y,a,a,a,0xFF); + } + } + + // Unlock + if(SDL_MUSTLOCK(Source)){ + SDL_UnlockSurface(Source); + } + if(SDL_MUSTLOCK(retval)){ + SDL_UnlockSurface(retval); + } + } + return retval; +} + +/*! \brief Creates a new surface and copies the content from the source + * \param Source Source surface + * \param Rect X and Y is used as source while W and H destinates size + * \return New SDL_Surface containing source graphics + */ +SDL_Surface *EDL_CopySurface(SDL_Surface *Source,SDL_Rect *Rect){ + SDL_Surface *retval=0; + if(Source){ + // Create destination + retval=EDL_CreateSurface(Source->w,Source->h); + if(Rect){ + SDL_Rect srect={Rect->x,Rect->y,Source->w,Source->h}; + SDL_Rect drect={0,0,Source->w,Source->h}; + EDL_BlitSurface(Source,&srect,retval,&drect); + } + else{ + EDL_BlitSurface(Source,0,retval,0); + } + } + return retval; +} + +#ifdef VILE_FEATURE_SCALER +/*! \brief Resizes one surface to another using HQ2X scaling + * \param Src Source surface + * \param Dst Destination surface + */ +void EDL_ScaleHQ2X(SDL_Surface *src,SDL_Surface *dst){ + // Initialize hq2x once + static bool hq2x_init=false; + if(!hq2x_init){ + InitHQ2X(); + hq2x_init=true; + } + +LogTest("a"); + SDL_Surface *tmpsrc=SDL_CreateRGBSurface(SDL_SWSURFACE, + src->w,src->h,16,0,0,0,0); + SDL_Surface *tmpdst=SDL_CreateRGBSurface(SDL_SWSURFACE, + (src->w*2)+4,(src->h*2)+4,16,0,0,0,0); + EDL_BlitSurface(src,0,tmpsrc,0); + if(SDL_MUSTLOCK(tmpsrc)){ + SDL_LockSurface(tmpsrc); + } + if(SDL_MUSTLOCK(tmpdst)){ + SDL_LockSurface(tmpdst); + } +LogTest("b:%d",tmpsrc->pitch); + hq2x_32((unsigned char*)tmpsrc->pixels, + (unsigned char*)tmpdst->pixels, + tmpsrc->w,tmpsrc->h,tmpsrc->pitch); +LogTest("c"); + if(SDL_MUSTLOCK(tmpsrc)){ + SDL_UnlockSurface(tmpsrc); + } + if(SDL_MUSTLOCK(tmpdst)){ + SDL_UnlockSurface(tmpdst); + } + EDL_ResizeSurface(tmpdst,dst,true); + SDL_FreeSurface(tmpsrc); + SDL_FreeSurface(tmpdst); +LogTest("DONE"); +} + +/*! \brief Resizes one surface to another using HQ2X scaling + * \param Src Source surface + * \param Dst Destination surface + */ +void EDL_ScaleHQ3X(SDL_Surface *src,SDL_Surface *dst){ + // Initialize hq3x once + static bool hq3x_init=false; + if(!hq3x_init){ + InitHQ3X(); + hq3x_init=true; + } + + SDL_Surface *tmpdst=SDL_CreateRGBSurface(SDL_SWSURFACE, + src->w*3,src->h*3,16,0,0,0,0); + if(SDL_MUSTLOCK(src)){ + SDL_LockSurface(src); + } + if(SDL_MUSTLOCK(tmpdst)){ + SDL_LockSurface(tmpdst); + } + hq2x_32((unsigned char*)src->pixels, + (unsigned char*)tmpdst->pixels, + src->w,src->h,src->w*4); + if(SDL_MUSTLOCK(src)){ + SDL_UnlockSurface(src); + } + if(SDL_MUSTLOCK(tmpdst)){ + SDL_UnlockSurface(tmpdst); + } + EDL_ResizeSurface(tmpdst,dst,true); + SDL_FreeSurface(tmpdst); + +} + +/*! \brief Resizes one surface to another using HQ4X scaling + * \param Src Source surface + * \param Dst Destination surface + */ +void EDL_ScaleHQ4X(SDL_Surface *src,SDL_Surface *dst){ + // Initialize hq4x once + static bool hq4x_init=false; + if(!hq4x_init){ + InitHQ4X(); + hq4x_init=true; + } + + SDL_Surface *tmpdst=SDL_CreateRGBSurface(SDL_SWSURFACE, + src->w*4,src->h*4,16,0,0,0,0); + if(SDL_MUSTLOCK(src)){ + SDL_LockSurface(src); + } + if(SDL_MUSTLOCK(tmpdst)){ + SDL_LockSurface(tmpdst); + } + hq4x_32((unsigned char*)src->pixels, + (unsigned char*)tmpdst->pixels, + src->w,src->h,src->w*4); + if(SDL_MUSTLOCK(src)){ + SDL_UnlockSurface(src); + } + if(SDL_MUSTLOCK(tmpdst)){ + SDL_UnlockSurface(tmpdst); + } + EDL_ResizeSurface(tmpdst,dst,true); + SDL_FreeSurface(tmpdst); +} +#endif + +/*! \brief Resizes one surface to another + * \param Src Source surface + * \param Dst Destination surface + * \param Smooth Wether to smooth the surface + */ +void EDL_ResizeSurface(SDL_Surface *Src,SDL_Surface *Dst,bool Smooth){ + if(Src->w==Dst->w && Src->h==Dst->h){ + // Blit directly + EDL_BlitSurface(Src,0,Dst,0); + } + else{ + // Resized blit + SDL_Surface *zs=zoomSurface(Src, + Dst->w/(double)Src->w, + Dst->h/(double)Src->h,Smooth?1:0); + if(zs){ + EDL_BlitSurface(zs,0,Dst,0); + SDL_FreeSurface(zs); + } + else{ + LogError("Resized blit failed!"); + EDL_BlitSurface(Src,0,Dst,0); + } + } +} + +/*! \brief Blends one surface onto another + * \param src Source surface + * \param srcrect Source rectangle + * \param dst Destination surface + * \param dstrect Destination rectangle + * + * Please note that the alpha values will be untouched in the result surface + */ +void EDL_BlendSurface( + SDL_Surface *src, SDL_Rect *srcrect, + SDL_Surface *dst, SDL_Rect *dstrect){ + // Assert source and destination rects + SDL_Rect s={0,0,src->w,src->h}; + SDL_Rect d={0,0,dst->w,dst->h}; + if(srcrect){ + s=*srcrect; + } + if(dstrect){ + d=*dstrect; + } + + // Limit blit to available data + d.w=EDL_MIN(d.w,s.w); + d.h=EDL_MIN(d.h,s.h); + s.w=EDL_MIN(d.w,s.w); + s.h=EDL_MIN(d.h,s.h); + + SDL_BlitSurface(src,&s,dst,&d); +} + +/*! \brief Copies one surface to another (Including alpha channel) + * \param src Source surface + * \param srcrect Source rectangle + * \param dst Destination surface + * \param dstrect Destination rectangle + * + * This method will copy all the specified pixels from source to destination + * surfaces, including the alpha channel when applicable, so no form of + * blending will take place. + */ +void EDL_BlitSurface( + SDL_Surface *src, SDL_Rect *srcrect, + SDL_Surface *dst, SDL_Rect *dstrect){ + // Assert source and destination rects + SDL_Rect s={0,0,src->w,src->h}; + SDL_Rect d={0,0,dst->w,dst->h}; + if(srcrect){ + s=*srcrect; + } + if(dstrect){ + d=*dstrect; + } + + // Limit blit to available data + d.w=EDL_MIN(d.w,s.w); + d.h=EDL_MIN(d.h,s.h); + s.w=EDL_MIN(d.w,s.w); + s.h=EDL_MIN(d.h,s.h); + + // Pass call to SDL + Uint32 flag=src->flags&SDL_SRCALPHA; + if(flag){ + src->flags&=~(SDL_SRCALPHA); + SDL_BlitSurface(src,&s,dst,&d); + src->flags|=SDL_SRCALPHA; + } + else{ + SDL_BlitSurface(src,&s,dst,&d); + } +} + +/*! \brief Sets alphachannel to a fixed value + * \param src Source surface + * \param srcrect Source rectangle + * \param Alpha Alpha value + */ +void EDL_SetAlpha(SDL_Surface *src, SDL_Rect *srcrect,Uint8 Alpha){ + // Get best rect + SDL_Rect srect={0,0,src->w,src->h}; + if(srcrect){ + srect.x=srcrect->x; + srect.y=srcrect->y; + srect.w=srcrect->w; + srect.h=srcrect->h; + } + srect.x=EDL_LIMIT(srect.x,0,src->w); + srect.y=EDL_LIMIT(srect.y,0,src->h); + srect.w=EDL_LIMIT(srect.w,0,src->w); + srect.h=EDL_LIMIT(srect.h,0,src->h); + + // Lock surfaces + if(SDL_MUSTLOCK(src)){ + if(SDL_LockSurface(src)<0){ + return; + } + } + + // Force alpha (Assuming 32bit surface) + srect.w+=srect.x; + srect.h+=srect.y; + for(int x=srect.x;xpixels+y*src->pitch/4+x; +#if SDL_BYTEORDER == SDL_BIG_ENDIAN + *pixel=((*pixel)&0xFFFFFF00)|Alpha; +#else + *pixel=((*pixel)&0x00FFFFFF)|(Alpha<<24); +#endif + } + } + + // Unlock + if(SDL_MUSTLOCK(src)){ + SDL_UnlockSurface(src); + } +} + diff --git a/engines/vileVN/common/edl_gfx.h b/engines/vileVN/common/edl_gfx.h new file mode 100644 index 0000000000..d3c9f4802b --- /dev/null +++ b/engines/vileVN/common/edl_gfx.h @@ -0,0 +1,84 @@ +/*! \unit Graphical extensions for SDL + * + * EDL is a ViLE-specific extension of SDL. EDL_GFX handles graphical tasks + * such as blitting and blending, rendering text and masking graphics. It + * usually overrides the default SDL methods and implements standard methods + * for handling graphics. + */ + +#ifndef _EDL_GFX_H_ +#define _EDL_GFX_H_ + +#include "edl_common.h" +#include +#include +#include +#include + +#ifdef VILE_FEATURE_SCALER +#include "../external/hq2x/hq2x.h" +#include "../external/hq3x/hq3x.h" +#include "../external/hq4x/hq4x.h" +extern void EDL_ScaleHQ2X(SDL_Surface *src,SDL_Surface *dst); +extern void EDL_ScaleHQ3X(SDL_Surface *src,SDL_Surface *dst); +extern void EDL_ScaleHQ4X(SDL_Surface *src,SDL_Surface *dst); +#endif + +// ----- Graphical API ----- +extern void EDL_BlendSurface( + SDL_Surface *src, SDL_Rect *srcrect, + SDL_Surface *dst, SDL_Rect *dstrect); + +extern void EDL_BlitSurface( + SDL_Surface *src, SDL_Rect *srcrect, + SDL_Surface *dst, SDL_Rect *dstrect); + +extern void EDL_BlitText( + uString Text,Uint32 Color, + SDL_Surface *dst,SDL_Rect *dstrect); + +extern void EDL_BlendText( + uString Text,Uint32 Color, + SDL_Surface *dst,SDL_Rect *dstrect); + +extern void EDL_ResizeSurface(SDL_Surface *src,SDL_Surface *dst,bool Smooth); + +extern void EDL_SetAlpha(SDL_Surface *src, SDL_Rect *srcrect,Uint8 Alpha); + +extern SDL_Surface *EDL_MapSurface(SDL_Surface *Source,SDL_Rect *Rect); + +extern SDL_Surface *EDL_MaskSurface(SDL_Surface *Bitmap, + SDL_Surface *Mask,SDL_Rect *Rect); + +extern SDL_Surface *EDL_ColorkeySurface(SDL_Surface *Bitmap, + Uint32 Key,SDL_Rect *Rect); + +extern SDL_Surface *EDL_ColorkeySurface(SDL_Surface *Bitmap,SDL_Rect *Rect); + +extern void EDL_SaveSurface(SDL_Surface * surface,uString File); + +extern SDL_Surface *EDL_CopySurface(SDL_Surface *Source,SDL_Rect *Rect); + +extern SDL_Surface *EDL_CreateSurface(int Width,int Height); + +extern SDL_Surface *EDL_CreateText(uString Text, + Uint32 Color,int Width,int Height); + +extern SDL_Surface *EDL_RenderText(TTF_Font *Font, + const uString &Text,SDL_Color fg); + +extern SDL_Surface *EDL_CreateMultilineText(uString Text, + Uint32 Color,int Width,int Height); + +extern bool EDL_SizeText(uString Text,int Size,int *Width,int *Height); + +extern Uint32 EDL_GetPixel(SDL_Surface * surface,Sint16 x,Sint16 y); + +extern void EDL_GetPixel(SDL_Surface * surface, + Sint16 x,Sint16 y,Uint8 *red,Uint8 *green,Uint8 *blue,Uint8 *alpha); + +extern void EDL_SetPixel(SDL_Surface * surface, + Sint16 x,Sint16 y,Uint8 red,Uint8 green,Uint8 blue,Uint8 alpha); + +#endif + diff --git a/engines/vileVN/common/guicon.cpp b/engines/vileVN/common/guicon.cpp new file mode 100644 index 0000000000..758e1726b0 --- /dev/null +++ b/engines/vileVN/common/guicon.cpp @@ -0,0 +1,50 @@ +#include "guicon.h" + +#ifdef VILE_ARCH_MICROSOFT +#ifdef VILE_BUILD_W32CONSOLE + +// maximum mumber of lines the output console should have +static const WORD MAX_CONSOLE_LINES = 500; + +void RedirectIOToConsole(){ + int hConHandle; + long lStdHandle; + CONSOLE_SCREEN_BUFFER_INFO coninfo; + FILE *fp; + + // allocate a console for this app + AllocConsole(); + + // set the screen buffer to be big enough to let us scroll text + GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE),&coninfo); + coninfo.dwSize.Y = MAX_CONSOLE_LINES; + SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE),coninfo.dwSize); + + // redirect unbuffered STDOUT to the console + lStdHandle = (long)GetStdHandle(STD_OUTPUT_HANDLE); + hConHandle = _open_osfhandle(lStdHandle, _O_TEXT); + fp = _fdopen( hConHandle, "w" ); + *stdout = *fp; + setvbuf( stdout, NULL, _IONBF, 0 ); + + // redirect unbuffered STDIN to the console + lStdHandle = (long)GetStdHandle(STD_INPUT_HANDLE); + hConHandle = _open_osfhandle(lStdHandle, _O_TEXT); + fp = _fdopen( hConHandle, "r" ); + *stdin = *fp; + setvbuf( stdin, NULL, _IONBF, 0 ); + + // redirect unbuffered STDERR to the console + lStdHandle = (long)GetStdHandle(STD_ERROR_HANDLE); + hConHandle = _open_osfhandle(lStdHandle, _O_TEXT); + fp = _fdopen( hConHandle, "w" ); + *stderr = *fp; + setvbuf( stderr, NULL, _IONBF, 0 ); + + // make cout, wcout, cin, wcin, wcerr, cerr, wclog and clog point to console as well + std::ios::sync_with_stdio(); +} + +#endif +#endif + diff --git a/engines/vileVN/common/guicon.h b/engines/vileVN/common/guicon.h new file mode 100644 index 0000000000..1959ae138b --- /dev/null +++ b/engines/vileVN/common/guicon.h @@ -0,0 +1,16 @@ +#ifndef _GUICON_H_ +#define _GUICON_H_ + +#ifdef VILE_ARCH_MICROSOFT +#ifdef VILE_BUILD_W32CONSOLE +#include +#include +#include +#include +#include +#include + +void RedirectIOToConsole(); +#endif +#endif +#endif diff --git a/engines/vileVN/common/inifile.cpp b/engines/vileVN/common/inifile.cpp new file mode 100644 index 0000000000..e0546dd9eb --- /dev/null +++ b/engines/vileVN/common/inifile.cpp @@ -0,0 +1,348 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "inifile.h" + +INIFile::INIFile(bool CaseSensitive){ + inisize=0; + inibuffer=0; + casesensitive=CaseSensitive; +} + +INIFile::~INIFile(){ + if(inibuffer){ + delete [] inibuffer; + } +} + +bool INIFile::WriteFile(uString Path){ + bool retval=false; + if(Path.length() && inibuffer && inisize){ + FILE *inifile=0; + if(Path.c_str()){ + inifile=fopen(Path.c_str(),"wb"); + } + if(inifile){ + retval=(fwrite(inibuffer,1,inisize,inifile)>0); + fclose(inifile); + } + } + return retval; +} + +bool INIFile::ReadFile(uString Path){ + bool retval=false; + FILE *inifile=0; + if(EDL_ReadableFile(Path)){ + inifile=fopen(Path.c_str(),"rb"); + } + if(inifile){ + fseek(inifile,0,SEEK_END); + int size=ftell(inifile); + fseek(inifile,0,SEEK_SET); + if(size>0){ + char *buffer=new char[size]; + if((int)fread(buffer,1,size,inifile)>0){ + // Data successfully read + if(inibuffer){ + delete [] inibuffer; + } + inibuffer=buffer; + inisize=size; + retval=true; + } + else{ + delete [] buffer; + } + } + fclose(inifile); + } + return retval; +} + +/*! \brief Searches for a section + * \param S Section to search for + * \param B Buffer to search + * \param L Length of buffer + * \return Index of section or -1 if failed + */ +int INIFile::ssection(uString S,char *B,unsigned int L){ + for(unsigned int i=0;i=0 && i0 && start0 && start0 && start +#include +#include +#include + +class INIFile { + private: + bool casesensitive; + char *inibuffer; + int inisize; + int ssection(uString S,char *B,unsigned int L); + int skey(uString S,uString K,char *B,unsigned int L); + int skey(uString K,char *B,unsigned int L); + public: + INIFile(bool CaseSensitive=true); + ~INIFile(); + bool Get(uString Section,uString Key,uString &Value); + bool Get(uString Section,uString Key,double &Value); + bool Get(uString Section,uString Key,int &Value); + bool Get(uString Key,uString &Value); + bool Get(uString Key,double &Value); + bool Get(uString Key,int &Value); + bool Set(uString Section,uString Key,uString Value); + bool Set(uString Section,uString Key,double Value); + bool Set(uString Section,uString Key,int Value); + bool ReadFile(uString Path); + bool WriteFile(uString Path); +}; + +#endif + diff --git a/engines/vileVN/common/log.cpp b/engines/vileVN/common/log.cpp new file mode 100644 index 0000000000..1f3fd2da4e --- /dev/null +++ b/engines/vileVN/common/log.cpp @@ -0,0 +1,200 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "log.h" + +#ifdef VILE_LOGGING_ENABLED + +/*! \brief Rebuilds a string from variable argument list + * \param String Formatted string + * \param Arg Argument list + * \returns Rebuilt string + */ +uString RebuildString(uString String,va_list Arg){ + const int size=1024*8; + static char buffer[size]; + vsnprintf(buffer,size,String.c_str(),Arg); + buffer[size-1]=0; + return buffer; +} + +/*! \brief Logs a message + * \param Text Formatted text + */ +void LogBase(LOGLEVEL Level,uString Text,...){ + // Gather arguments + va_list arg; + va_start(arg,Text); + Text=RebuildString(Text,arg); + va_end(arg); + + if(Level>=MINLOGLEVEL){ + // Optional logging to file + if(Cfg::System::Logfile.length()){ + FILE *tf=fopen(Cfg::System::Logfile.c_str(),"ab"); + if(tf){ + fwrite(Text.c_str(),1,Text.length(),tf); + fwrite("\r\n",2,1,tf); + fclose(tf); + } + } + + // Logg to standard output + FILE *tf=Level==LLERROR?stderr:stdout; + if(Cfg::System::Logcolor){ + char ansib[32]; + int FG=LOG_WHITE; + if(Level==LLERROR) FG=COLOR_ERROR; + if(Level==LLWARNING) FG=COLOR_WARNING; + if(Level==LLMESSAGE) FG=COLOR_MESSAGE; + if(Level==LLDEBUG) FG=COLOR_DEBUG; + int ansil=sprintf(ansib,"%c[%d;%dm",0x1B,0,FG); + fwrite(ansib,ansil,1,tf); + fwrite(Text.c_str(),Text.length(),1,tf); + ansil=sprintf(ansib,"%c[%d;%d;%dm ",0x1B,0,0,0); + fwrite(ansib,ansil,1,tf); + } + else{ + fwrite(Text.c_str(),Text.length(),1,tf); + } + fwrite("\r\n",2,1,tf); + +#ifdef LOGFLUSH + fflush(tf); +#endif + } +} + +/*! \brief Logs a string without adding any formatting or newlines + * \param Text Formatted text + */ +void LogRaw(LOGLEVEL Level,uString Text,...){ + // Gather arguments + va_list arg; + va_start(arg,Text); + Text=RebuildString(Text,arg); + va_end(arg); + + if(Level>=MINLOGLEVEL){ + // Optional logging to file + if(Cfg::System::Logfile.length()){ + FILE *tf=fopen(Cfg::System::Logfile.c_str(),"ab"); + if(tf){ + fwrite(Text.c_str(),1,Text.length(),tf); + fclose(tf); + } + } + + // Logg to standard output + FILE *tf=Level==LLERROR?stderr:stdout; + fwrite(Text.c_str(),Text.length(),1,tf); + + // Always flush (No newlines) + fflush(tf); + } +} + +/*! \brief Logs a basic message + * \param Text Formatted text + */ +void LogMessage(uString Text,...){ + // Gather arguments + va_list arg; + va_start(arg,Text); + Text=RebuildString(Text,arg); + va_end(arg); + + // Handle message + LogBase(LLMESSAGE,Text); +} + +/*! \brief Logs a message if the verbose flag is set + * \param Text Formatted text + */ +void LogVerbose(uString Text,...){ + if(Cfg::System::Verbose){ + // Gather arguments + va_list arg; + va_start(arg,Text); + Text=RebuildString(Text,arg); + va_end(arg); + + // Handle message + LogBase(LLDEBUG,Text); + } +} + +/*! \brief Logs an error message + * \param Text Formatted text + */ +void LogError(uString Text,...){ + // Gather arguments + va_list arg; + va_start(arg,Text); + Text=RebuildString(Text,arg); + va_end(arg); + + // Handle message + LogBase(LLERROR,Text); +} + +/*! \brief Logs temporary debug message + * \param Text Formatted text + */ +void LogWarning(uString Text,...){ + // Gather arguments + va_list arg; + va_start(arg,Text); + Text=RebuildString(Text,arg); + va_end(arg); + + // Handle message + LogBase(LLWARNING,Text); +} + +/*! \brief Logs temporary debug message + * \param Text Formatted text + */ +void LogTest(uString Text,...){ + // Gather arguments + va_list arg; + va_start(arg,Text); + Text=RebuildString(Text,arg); + va_end(arg); + + // Handle message + LogBase(LLWARNING,Text); +} + +#ifdef VILE_LOGGING_DEBUG +/*! \brief Logs a message if the verbose flag is set + * \param Text Formatted text + */ +void LogDebug(uString Text,...){ + if(Cfg::System::Verbose){ + // Gather arguments + va_list arg; + va_start(arg,Text); + Text=RebuildString(Text,arg); + va_end(arg); + + // Handle message + LogBase(LLDEBUG,Text); + } +} +#endif // Endof Debugger enabled + +#endif // Endff Disable logging + diff --git a/engines/vileVN/common/log.h b/engines/vileVN/common/log.h new file mode 100644 index 0000000000..2f38d387ca --- /dev/null +++ b/engines/vileVN/common/log.h @@ -0,0 +1,70 @@ +/*! \unit log.h + * \brief Standard logging interface + */ +#ifndef _LOG_H_ +#define _LOG_H_ + +// Common includes +#include +#include "ustring.h" +#include "cfg.h" + +// Define terminal colors +#define LOG_BLACK 30 +#define LOG_RED 31 +#define LOG_GREEN 32 +#define LOG_YELLOW 33 +#define LOG_BLUE 34 +#define LOG_MAGENTA 35 +#define LOG_CYAN 36 +#define LOG_WHITE 37 + +// Default colors +#define COLOR_ERROR LOG_RED +#define COLOR_WARNING LOG_BLUE +#define COLOR_MESSAGE LOG_WHITE +#define COLOR_DEBUG LOG_GREEN + +// Set minimum logging level +#define MINLOGLEVEL LLDEBUG + +// Uncomment to flush every write (In case of crash) +#define LOGFLUSH + +// Uncomment to get colors +#define LOGCOLOR + +// Define levels +enum LOGLEVEL { + LLDEBUG=0, + LLMESSAGE, + LLWARNING, + LLERROR +}; + +#ifdef VILE_LOGGING_ENABLED +extern void LogRaw(LOGLEVEL Level,uString Text,...); +extern void LogBase(LOGLEVEL Level,uString Text,...); +extern void LogMessage(uString Text,...); +extern void LogVerbose(uString Text,...); +extern void LogWarning(uString Text,...); +extern void LogError(uString Text,...); +extern void LogTest(uString Text,...); +#else +#define LogBase(Level,Channel,Text,...) ; +#define LogRaw(Level,Channel,Text,...) ; +#define LogMessage(Text,...) ; +#define LogVerbose(Text,...) ; +#define LogWarning(Text,...) ; +#define LogError(Text,...) ; +#define LogTest(Text,...) ; +#endif + +#ifdef VILE_LOGGING_DEBUG +extern void LogDebug(uString Text,...); +#else +#define LogDebug(Text,...) ; +#endif + +#endif + diff --git a/engines/vileVN/common/redblack.cpp b/engines/vileVN/common/redblack.cpp new file mode 100644 index 0000000000..2293aa193b --- /dev/null +++ b/engines/vileVN/common/redblack.cpp @@ -0,0 +1,404 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "redblack.h" + +RedBlackLeave::RedBlackLeave(){ +}; + +RedBlackLeave::~RedBlackLeave(){ +}; + +RedBlackNode::RedBlackNode(RedBlackLeave *Leave){ + entry=Leave; +}; + +RedBlackNode::~RedBlackNode(){ + delete entry; +}; + +/*! \brief Contructor for a new tree object + * \param Nil Node which will always stay on top + * \param Root Node which will always stay at the bottom + * + * Nil and Root must be leave objects' whose Compare methods returns + * the min or max of the objects range. This asserts top and bottom of + * the stack without doublechecking pointers. + */ +RedBlackTree::RedBlackTree(RedBlackLeave *Nil,RedBlackLeave *Root) +{ + nil=new RedBlackNode(Nil); + nil->left=nil->right=nil->parent=nil; + nil->color=RB_BLACK; + root=new RedBlackNode(Root); + root->parent=root->left=root->right=nil; + root->color=RB_BLACK; + count=0; +} + +/*!\brief Rotates x to the left of its parent + * \param x Node to rotate + */ +void RedBlackTree::LeftRotate(RedBlackNode* x) { + RedBlackNode* y; + y=x->right; + x->right=y->left; + if(y->left!=nil){ + y->left->parent=x; + } + y->parent=x->parent; + if( x == x->parent->left) { + x->parent->left=y; + } + else{ + x->parent->right=y; + } + y->left=x; + x->parent=y; +} + +/*!\brief Rotates y to the right of its parent + * \param y Node to rotate + */ +void RedBlackTree::RightRotate(RedBlackNode* y) { + RedBlackNode* x; + x=y->left; + y->left=x->right; + if(nil!=x->right){ + x->right->parent=y; + } + x->parent=y->parent; + if(y==y->parent->left){ + y->parent->left=x; + } + else{ + y->parent->right=x; + } + x->right=y; + y->parent=x; +} + +/*!\brief Helper function to insert a leaf + * \param z Lead to insert + * \param Mode Search mode + */ +void RedBlackTree::TreeInsertHelp(RedBlackNode* z,int Mode) { + /* This function should only be called by RedBlackTree::Insert */ + RedBlackNode* x; + RedBlackNode* y; + z->left=z->right=nil; + y=root; + x=root->left; + while( x != nil) { + y=x; + if(x->entry->Compare(z->entry,Mode)>0){ + x=x->left; + } + else{ + x=x->right; + } + } + z->parent=y; + if((y==root)||(y->entry->Compare(z->entry,Mode)>0)){ + y->left=z; + } + else{ + y->right=z; + } +} + +/*!\brief Insert a leaf + * \param z Lead to insert + * \param Mode Search mode + */ +RedBlackNode * RedBlackTree::Insert(RedBlackLeave * Leave,int Mode) +{ + RedBlackNode * y; + RedBlackNode * x; + RedBlackNode * node; + count++; + x = new RedBlackNode(Leave); + TreeInsertHelp(x,Mode); + node = x; + x->color=RB_RED; + while(x->parent->color){ + if(x->parent==x->parent->parent->left){ + y=x->parent->parent->right; + if(y->color){ + x->parent->color=RB_BLACK; + y->color=RB_BLACK; + x->parent->parent->color=RB_RED; + x=x->parent->parent; + } + else{ + if(x==x->parent->right){ + x=x->parent; + LeftRotate(x); + } + x->parent->color=RB_BLACK; + x->parent->parent->color=RB_RED; + RightRotate(x->parent->parent); + } + } + else{ + y=x->parent->parent->left; + if(y->color){ + x->parent->color=RB_BLACK; + y->color=RB_BLACK; + x->parent->parent->color=RB_RED; + x=x->parent->parent; + } + else{ + if(x==x->parent->left){ + x=x->parent; + RightRotate(x); + } + x->parent->color=RB_BLACK; + x->parent->parent->color=RB_RED; + LeftRotate(x->parent->parent); + } + } + } + root->left->color=RB_BLACK; + return node; +} + +/*! \brief Gets the succeeding leave + * \param x Leave to get the successor of + * \return Successor of x or NULL if failed + */ +RedBlackNode * RedBlackTree::GetSuccessorOf(RedBlackNode * x) const +{ + RedBlackNode* y; + if(nil!=(y=x->right)){ + // Get the minium of the right subtree of x + while(y->left!=nil){ + y=y->left; + } + return y; + } + else{ + y=x->parent; + while(x==y->right){ + x=y; + y=y->parent; + } + return y==root?nil:y; + } +} + +/*! \brief Gets the preceeding leave + * \param x Leave to get the predecessor of + * \return Predecessor of x or NULL if failed + */ +RedBlackNode * RedBlackTree::GetPredecessorOf(RedBlackNode * x) const { + RedBlackNode* y; + if(nil!=(y=x->left)){ + // Get maximum of the left subtree of x + while(y->right!=nil){ + y=y->right; + } + return y; + } + else{ + y=x->parent; + while(x==y->left){ + if(y==root){ + return nil; + } + x=y; + y=y->parent; + } + return y; + } +} + +RedBlackTree::~RedBlackTree() { + Destroy(root); + delete nil; +} + +/*! \brief Recursively destroy nodes + */ +void RedBlackTree::Destroy(RedBlackNode *Node){ + if(Node && Node!=nil) { + Destroy(Node->left); + Destroy(Node->right); + Node->left=0; + Node->right=0; + delete Node; + } +} + +RedBlackLeave *RedBlackTree::Search(RedBlackLeave *x,int Mode){ + RedBlackNode *tmpptr=root; + while(tmpptr){ + if(tmpptr==nil){ + return 0; + } + else{ + int t=tmpptr->entry->Compare(x,Mode); + if(t>0){ + tmpptr=tmpptr->left; + } + else if(t<0){ + tmpptr=tmpptr->right; + } + else{ + return tmpptr->entry; + } + } + } + return 0; +} + +void RedBlackTree::Enumerate(RedBlackNode *Node, + RedBlackLeave **Buffer,int &Count,int &Size){ + if(Node==nil || Count==Size){ + // Stop search + } + else{ + // Recursively add nodex + Buffer[Count++]=Node->entry; + Enumerate(Node->left,Buffer,Count,Size); + Enumerate(Node->right,Buffer,Count,Size); + } +} + +int RedBlackTree::Enumerate(RedBlackLeave **Buffer,int Size){ + int cnt=0; + Enumerate(root->left,Buffer,cnt,Size); + Enumerate(root->right,Buffer,cnt,Size); + return cnt; +} + +int RedBlackTree::Count(){ + return count; +} + +/*! \brief Restores red-black properties after node removal + * \param x Child of the spliced out node + */ +void RedBlackTree::DeleteFixUp(RedBlackNode* x) { + RedBlackNode *w; + RedBlackNode *rootLeft=root->left; + while((!x->color) && (rootLeft!=x)){ + if(x==x->parent->left){ + w=x->parent->right; + if(w->color){ + w->color=RB_BLACK; + x->parent->color=RB_RED; + LeftRotate(x->parent); + w=x->parent->right; + } + if((!w->right->color) && (!w->left->color)){ + w->color=RB_RED; + x=x->parent; + } + else{ + if(!w->right->color){ + w->left->color=RB_BLACK; + w->color=RB_RED; + RightRotate(w); + w=x->parent->right; + } + w->color=x->parent->color; + x->parent->color=RB_BLACK; + w->right->color=RB_BLACK; + LeftRotate(x->parent); + x=rootLeft; + } + } + else{ + w=x->parent->left; + if(w->color){ + w->color=RB_BLACK; + x->parent->color=RB_RED; + RightRotate(x->parent); + w=x->parent->left; + } + if((!w->right->color) && (!w->left->color)){ + w->color=RB_RED; + x=x->parent; + } + else{ + if(!w->left->color){ + w->right->color=RB_BLACK; + w->color=RB_RED; + LeftRotate(w); + w=x->parent->left; + } + w->color=x->parent->color; + x->parent->color=RB_BLACK; + w->left->color=RB_BLACK; + RightRotate(x->parent); + x=rootLeft; + } + } + } + x->color=RB_BLACK; +} + +/*! \brief Deletes a node from the tree + * \param z Node to be deleted + */ +RedBlackLeave * RedBlackTree::DeleteNode(RedBlackNode * z){ + RedBlackNode* y; + RedBlackNode* x; + RedBlackLeave * retval = z->entry; + y=((z->left==nil) || (z->right == nil)) ? z : GetSuccessorOf(z); + x=(y->left==nil) ? y->right : y->left; + if(root==(x->parent=y->parent)){ + root->left=x; + } + else{ + if(y==y->parent->left){ + y->parent->left=x; + } + else{ + y->parent->right=x; + } + } + if(y!=z){ + y->left=z->left; + y->right=z->right; + y->parent=z->parent; + z->left->parent=z->right->parent=y; + if(z==z->parent->left){ + z->parent->left=y; + } + else{ + z->parent->right=y; + } + if(!(y->color)){ + y->color = z->color; + DeleteFixUp(x); + } + else{ + y->color = z->color; + } + delete z; + count--; + } + else{ + if(!(y->color)){ + DeleteFixUp(x); + } + delete y; + count--; + } + return retval; +} + diff --git a/engines/vileVN/common/redblack.h b/engines/vileVN/common/redblack.h new file mode 100644 index 0000000000..79367b2309 --- /dev/null +++ b/engines/vileVN/common/redblack.h @@ -0,0 +1,70 @@ +#ifndef E_REDBLACK_TREE +#define E_REDBLACK_TREE + +#include +#include +#include +#include +#include +#include + +#define RB_RED true +#define RB_BLACK false + +/*! \class RedBlackLeave + * \brief Base class for searchable items + */ +class RedBlackLeave { + public: + RedBlackLeave(); + virtual ~RedBlackLeave(); + virtual int Compare(RedBlackLeave *Leave,int Mode)=0; +}; + +/*! \class RedBlackNode + * \brief Internal class for managing items + */ +class RedBlackNode { + private: + friend class RedBlackTree; + RedBlackLeave *entry; + RedBlackNode *left; + RedBlackNode *right; + RedBlackNode *parent; + bool color; + public: + RedBlackNode(RedBlackLeave *Leave); + ~RedBlackNode(); +}; + +class RedBlackTree { + private: + // Helper funcions + void LeftRotate(RedBlackNode *Node); + void RightRotate(RedBlackNode *Node); + void TreeInsertHelp(RedBlackNode *Node,int Mode); + void FixUpMaxHigh(RedBlackNode *Node); + void DeleteFixUp(RedBlackNode *Nodw); + RedBlackNode *GetPredecessorOf(RedBlackNode *Node) const; + RedBlackNode *GetSuccessorOf(RedBlackNode *Node) const; + + // Recursive iterators + void Destroy(RedBlackNode *Node); + void Enumerate(RedBlackNode *Node,RedBlackLeave **B,int &C,int &L); + + // Object data + RedBlackNode *root; + RedBlackNode *nil; + int count; + public: + RedBlackTree(RedBlackLeave *Nil,RedBlackLeave *Root); + ~RedBlackTree(); + RedBlackLeave *DeleteNode(RedBlackNode *Node); + RedBlackNode *Insert(RedBlackLeave *Leave,int Mode); + RedBlackLeave *Search(RedBlackLeave *Leave,int Mode); + int Enumerate(RedBlackLeave **Buffer,int Size); + int Count(); +}; + + +#endif diff --git a/engines/vileVN/common/savegame.cpp b/engines/vileVN/common/savegame.cpp new file mode 100644 index 0000000000..326a0efaab --- /dev/null +++ b/engines/vileVN/common/savegame.cpp @@ -0,0 +1,617 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "savegame.h" + +Savegame::Savegame(uString Gamecode,int Index){ + filename=Savename(Gamecode,Index); + buffer=0; + length=0; +} + +Savegame::~Savegame(){ + Clear(); +} + +/*! \brief Generates a filename for the savegame + * \param GameID Unique game identifier + * \param Index Savegame index for this game + * \returns Name for the savegame + */ +uString Savegame::Savename(uString GameID,int Index){ + // Compile filename + char fnbuffer[GameID.length()+32]; + sprintf(fnbuffer,"%s%3.3d",GameID.c_str(),Index); + uString path=Cfg::Path::save; + if(path.length()){ + path+="/"; + } + return path+fnbuffer; +} + +/*! \brief Searches current buffer for a named resource + * \param Name Resource name to search for + * \param Start Start of resource if found + * \param End End of resource if found + * \return True if a valid entry was found + */ +bool Savegame::search(uString Name,Uint32 *Start,Uint32 *End){ + if(buffer && Name.length()){ + for(unsigned int i=0;i=Pos+Length+SHLENGTH); + if(retval){ + int j=Pos; + Uint32 start=Pos+SHLENGTH; + Uint32 end=start+Length; + for(unsigned int i=0;i>8)&0xFF; + buffer[j++]=(start>>16)&0xFF; + buffer[j++]=(start>>24)&0xFF; + buffer[j++]=(end)&0xFF; + buffer[j++]=(end>>8)&0xFF; + buffer[j++]=(end>>16)&0xFF; + buffer[j++]=(end>>24)&0xFF; + for(unsigned int i=0;i0){ + if(buffer){ + delete [] buffer; + } + buffer=newbuffer; + length=rs; + retval=true; + } + } + fclose(rf); + } + return retval; +} + +/*! \brief Writes current buffer to file + * \returns True if data was successfully written + */ +bool Savegame::Write(){ + bool retval=false; + if(buffer){ + FILE *wf=fopen(filename.c_str(),"wb"); + if(wf){ + fwrite(buffer,1,length,wf); + fclose(wf); + retval=true; + } + } + return retval; +} + +/*! \brief Tests wether savegame file exists + * \return True if file exists and size is nonzero + */ +bool Savegame::Exists(){ + FILE *tf=fopen(filename.c_str(),"r"); + if(tf!=NULL){ + fseek(tf,0,SEEK_END); + int l=ftell(tf); + fclose(tf); + return l>0; + } + else{ + return false; + } +} + +/*! \brief Flushes buffered content + */ +void Savegame::Clear(){ + if(buffer){ + delete [] buffer; + buffer=0; + length=0; + } +} + +/*! \brief Flushes buffered content and deletes existing file + */ +void Savegame::Delete(){ + Clear(); + unlink(filename.c_str()); +} + +/*! \brief Embeds a bitmap in the savestream + * \param Name Name of the saved resource + * \param Surface Surface to store + * \param W Optional parameter to resize the surface before storing it + * \param H Optional parameter to resize the surface before storing it + * + * The surface will be converted to a stream of bytes and compressed with + * zlib before it is stored. This preserves alpha and provides lossless + * compression, but the current implementation will only work for 32bit + * surfaces. + */ +void Savegame::SaveSurface(uString Name,SDL_Surface *Surface,int W,int H){ + if(Surface && Surface->w && Surface->h){ + // Resize bitmap + SDL_Surface *target=Surface; + if(W && H){ + double rx=W/(double)Surface->w; + double ry=H/(double)Surface->h; + target=zoomSurface(Surface,rx,ry,1); + } + + // Convert target surface to bytes + Uint16 w=target->w; + Uint16 h=target->h; + Uint8 b=target->format->BytesPerPixel; + int size=2+2+1+(w*h*b); + Uint8 *buffer=new Uint8[size]; + int o=0; + buffer[o++]=(w>>8)&0xFF; + buffer[o++]=w&0xFF; + buffer[o++]=(h>>8)&0xFF; + buffer[o++]=h&0xFF; + buffer[o++]=b*8; + for(int y=0;ypixels+y*target->pitch/4+x; + buffer[o++]=((*pixel)>>24)&0xFF; + buffer[o++]=((*pixel)>>16)&0xFF; + buffer[o++]=((*pixel)>>8)&0xFF; + buffer[o++]=(*pixel)&0xFF; + } + } + + // Compress buffer with zlib + long unsigned int csize=(size*1.1)+12; + Uint8 *cbuffer=new Uint8[csize+8]; + int result=compress(cbuffer+8,&csize,buffer,size); + if(result==Z_OK){ + cbuffer[0]='Z'; + cbuffer[1]='L'; + cbuffer[2]='I'; + cbuffer[3]='B'; + cbuffer[4]=(size>>24)&0xFF; + cbuffer[5]=(size>>16)&0xFF; + cbuffer[6]=(size>>8)&0xFF; + cbuffer[7]=size&0xFF; + SaveBuffer(Name,cbuffer,csize+8); + } + else{ + LogError("ZLib error: %d",result); + } + + // Clean up + delete [] cbuffer; + delete [] buffer; + if(target!=Surface){ + SDL_FreeSurface(target); + } + } +} + +/*! \brief Extracts a bitmap from the loadstream + * \param Name Name of the saved resource + * \param Surface Pointer for new surface + * \param W Optional parameter to resize the surface after loading it + * \param H Optional parameter to resize the surface after loading it + * \return Extracted bitmap or NULL if failed + * + * The new surface must be freed by the caller + */ +bool Savegame::LoadSurface(uString Name,SDL_Surface **Surface,int W,int H){ + Uint8 *b; + Uint32 l; + bool retval=false; + if(LoadBuffer(Name.c_str(),&b,&l)){ + *Surface=0; + if(b[0]=='B' && b[1]=='M'){ + // Load as bitmap (Backwards compability only) + SDL_RWops *ops=SDL_RWFromMem(b,l); + *Surface=SDL_LoadBMP_RW(ops,1); + } + else if(b[0]=='Z' && b[1]=='L' && b[2]=='I' && b[3]=='B'){ + // Decompress buffer with zlib (ViLE>=0.4.10) + long unsigned int size=0; + size|=b[5]<<24; + size|=b[6]<<16; + size|=b[7]<<8; + size|=b[8]; + size=(size*1.1)+12; + Uint8 *buffer=new Uint8[size]; + int result=uncompress(buffer,&size,b+8,l-8); + if(result==Z_OK){ + Uint16 w=(buffer[0]<<8)|buffer[1]; + Uint16 h=(buffer[2]<<8)|buffer[3]; + Uint16 b=buffer[4]; + int i=5; + *Surface=EDL_CreateSurface(w,h); + SDL_Surface *s=*Surface; + for(int y=0;ypixels+y*s->pitch/4+x; + *pixel=0; + *pixel|=buffer[i++]<<24; + *pixel|=buffer[i++]<<16; + *pixel|=buffer[i++]<<8; + *pixel|=buffer[i++]; + } + } + } + else{ + LogError("ZLib error: %d",result); + } + delete [] buffer; + } + else{ + // Report errors + LogError("Invalid surface header: %c%c%c%c",b[0],b[1],b[2],b[3]); + } + + // Resize if applicable + if(*Surface && W && H && W!=(*Surface)->w && H!=(*Surface)->h){ + double rx=W/(double)(*Surface)->w; + double ry=H/(double)(*Surface)->h; + SDL_Surface *rs=zoomSurface(*Surface,rx,ry,1); + SDL_FreeSurface(*Surface); + *Surface=rs; + } + + // Clean up the mess + retval=*Surface; + delete [] b; + } + return retval; +} + +/*! \brief Saves a named variable + * \param Name Name of the variable + * \param Value Value of the variable + */ +void Savegame::SaveUint8(uString Name,Uint8 Value){ + SaveBuffer(Name,&Value,1); +} + +/*! \brief Saves a named variable + * \param Name Name of the variable + * \param Value Value of the variable + */ +void Savegame::SaveUint16(uString Name,Uint16 Value){ + Uint8 b[2]; + b[0]=(Value)&0xFF; + b[1]=(Value>>8)&0xFF; + SaveBuffer(Name,b,2); +} + +/*! \brief Saves a named variable + * \param Name Name of the variable + * \param Value Value of the variable + */ +void Savegame::SaveUint32(uString Name,Uint32 Value){ + Uint8 b[4]; + b[0]=(Value)&0xFF; + b[1]=(Value>>8)&0xFF; + b[2]=(Value>>16)&0xFF; + b[3]=(Value>>24)&0xFF; + SaveBuffer(Name,b,4); +} + +/*! \brief Saves a list of strings + * \param Name Name of the stringlist + * \param List List of strings + */ +void Savegame::SaveStringList(uString Name,Stringlist *List){ + if(List && List->GetCount()){ + uString text; + char name[32]; + int count=List->GetCount(); + SaveUint16(Name+".length",count); + for(int i=0;iGetString(i,&text) && text.length()){ + sprintf(name,"%s.%d",Name.c_str(),i); + SaveString(name,text); + } + } + } +} + +/*! \brief Saves a named variable + * \param Name Name of the variable + * \param Value Value of the variable + */ +void Savegame::SaveString(uString Name,uString Value){ + SaveBuffer(Name,(Uint8*)Value.c_str(),Value.length()); +} + +/*! \brief Saves a list of values + * \param Name Name of the vector + * \param Vector List of values + */ +void Savegame::SaveVector(uString Name,DVector *Vector){ + Uint8 *buffer; + Uint32 length; + if(Vector && Vector->GetBuffer(&buffer,&length)){ + SaveBuffer(Name,buffer,length); + } +} + +/*! \brief Saves a buffer using a resource name + * \param Name Resource name + * \param Buffer Source data + * \param Length Size of source data + */ +void Savegame::SaveBuffer(uString Name,Uint8 *Buffer,Uint32 Length){ + Uint32 start,end; + if(!buffer){ + // Write directly + length=Length+SHLENGTH; + buffer=new Uint8[length]; + write(Name,0,Buffer,Length); + } + else if(search(Name,&start,&end)){ + // Inject into existing + Uint32 newlength=length+Length+SHLENGTH-((end-start)+SHLENGTH); + Uint8 *newbuffer=new Uint8[newlength]; + int j=0; + for(unsigned int i=0;i>8)&0xFF; + newbuffer[j++]=(dstart>>16)&0xFF; + newbuffer[j++]=(dstart>>24)&0xFF; + newbuffer[j++]=(dend)&0xFF; + newbuffer[j++]=(dend>>8)&0xFF; + newbuffer[j++]=(dend>>16)&0xFF; + newbuffer[j++]=(dend>>24)&0xFF; + for(unsigned int k=sstart;kSetBuffer(buffer,length); + delete [] buffer; + retval=true; + } + return retval; +} + +/*! \brief Loads a named list of strings + * \param Name Name of the list + * \param List Pointer to local list + * \returns True if the list was found (and copied) + */ +void Savegame::LoadStringList(uString Name,Stringlist *List){ + if(List){ + Uint16 length; + char name[32]; + uString text; + if(LoadUint16(Name+".length",&length)){ + for(int i=0;iSetString(i,text); + } + } + } + } +} + +/*! \brief Loads a named string + * \param Name Name of the string + * \param Value Pointer to local variable + * \returns True if the string was found (and copied) + */ +bool Savegame::LoadString(uString Name,uString *Value){ + Uint8 *b; + Uint32 l; + bool retval=false; + if(LoadBuffer(Name,&b,&l)){ + char tb[l+1]; + for(unsigned int i=0;i +#include +#include +#include "log.h" +#include "dvector.h" +#include "stringlist.h" +#include "edl_gfx.h" + +#define SNLENGTH 32 //!< Length of resource names +#define SHLENGTH (SNLENGTH+8) //!< Length of resource header + +class Savegame { + private: + uString filename; + Uint8 *buffer; + unsigned int length; + bool write(uString Name,Uint32 Pos,Uint8 *Buffer,Uint32 Length); + bool search(uString Name,Uint32 *Start,Uint32 *End); + public: + Savegame(uString Gamecode,int Index); + ~Savegame(); + + // Resolve filenames + static uString Savename(uString GameID,int Index); + + // File interface + bool Write(); + bool Read(); + void Clear(); + void Delete(); + bool Exists(); + + // Value interface + void SaveBuffer(uString Name,Uint8 *Buffer,Uint32 Length); + void SaveSurface(uString Name,SDL_Surface *Surface,int W=0,int H=0); + void SaveVector(uString Name,DVector *Vector); + void SaveStringList(uString Name,Stringlist *List); + void SaveString(uString Name,uString Value); + void SaveUint8(uString Name,Uint8 Value); + void SaveUint16(uString Name,Uint16 Value); + void SaveUint32(uString Name,Uint32 Value); + bool LoadBuffer(uString Name,Uint8 **Buffer,Uint32 *Length); + bool LoadSurface(uString Name,SDL_Surface **Surface,int W=0,int H=0); + bool LoadVector(uString Name,DVector *Vector); + void LoadStringList(uString Name,Stringlist *List); + bool LoadString(uString Name,uString *Value); + bool LoadUint8(uString Name,Uint8 *Value); + bool LoadUint16(uString Name,Uint16 *Value); + bool LoadUint32(uString Name,Uint32 *Value); +}; + +#endif + diff --git a/engines/vileVN/common/stringlist.cpp b/engines/vileVN/common/stringlist.cpp new file mode 100644 index 0000000000..73be313455 --- /dev/null +++ b/engines/vileVN/common/stringlist.cpp @@ -0,0 +1,162 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "stringlist.h" + +Stringlist::Stringlist(const Stringlist &Source){ + stringlist=0; + count=0; + (*this)=Source; +} + +/*! \brief Preloads a given number of empty string objects + * \param Preload Number of strings to preload + * + * Preloading empty strings gives a hefty speed advantage as you + * do not have to reload and the string objects every time you + * add a new one. + */ +Stringlist::Stringlist(int Preload){ + if(Preload>0){ + stringlist=new uString[Preload]; + count=Preload; + } + else{ + stringlist=0; + count=0; + } +} + +Stringlist::~Stringlist(){ + if(stringlist){ + delete [] stringlist; + } + stringlist=0; + count=0; +} + +Stringlist &Stringlist::operator=(const Stringlist &Source) { + if(this!=&Source){ + Clear(); + int preload=Source.GetCount(); + stringlist=new uString[preload]; + count=preload; + for(int i=0;i0){ + retval=retval.substr(0,l-1); + } + return retval; +} + +/*! \brief Counts number of strings in the object + * \return Number of strings in the object + */ +int Stringlist::GetCount() const{ + return count; +} + +/*! \brief Removes all loaded strings + */ +void Stringlist::Clear(){ + if(stringlist){ + delete [] stringlist; + stringlist=0; + count=0; + } +} + +/*! \brief Append a string and the end of the list + * \param Text Text to add + */ +void Stringlist::AddString(uString Text){ + SetString(count,Text); +} + +/*! \brief Adds a list of strings to the end of the list + * \param List List of strings to add + */ +void Stringlist::AddStringlist(Stringlist List){ + int length=List.GetCount(); + for(int i=0;i +#include "log.h" + +class Stringlist { + private: + uString *stringlist; + int count; + public: + Stringlist(int Preload=0); + Stringlist(const Stringlist &Source); + Stringlist &operator=(const Stringlist &Source); + ~Stringlist(); + void SetString(int Pos,uString Text); + void AddString(uString Text); + void AddStringlist(Stringlist List); + uString GetString(int Pos); + int GetString(uString Text); + bool GetString(int Pos,uString *Text); + int GetCount() const; + void Clear(); + uString Enumerate(); +}; + +#endif + diff --git a/engines/vileVN/common/ustring.cpp b/engines/vileVN/common/ustring.cpp new file mode 100644 index 0000000000..70bb396b81 --- /dev/null +++ b/engines/vileVN/common/ustring.cpp @@ -0,0 +1,651 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "ustring.h" +#include +#include +#include "edl_common.h" +#include "log.h" + +// Include utf8cpp backend +#if VILE_UNICODE_SAFE +#include "../external/utf8cpp/checked.h" +#endif +#include "../external/utf8cpp/unchecked.h" + + +// ANSI constructors +uString::uString(){ + cbytes=0; + cpoints=0; +} + +uString::uString(const aString *Src){ + buffer=CHARTOUTF8((const Uint8*)Src->c_str(),cbytes,cpoints); +} + +uString::uString(const char *Src){ + buffer=CHARTOUTF8((const Uint8*)Src,cbytes,cpoints); +} + +uString::uString(const char &Src){ + aString tmp; + tmp+=Src; + buffer=CHARTOUTF8((const Uint8*)tmp.c_str(),cbytes,cpoints); +} + +uString::uString(const uString &Src){ + cbytes=Src.cbytes; + cpoints=Src.cpoints; + buffer=Src.buffer; +} + +uString::uString(const aString &Src){ + buffer=CHARTOUTF8((const Uint8*)Src.c_str(),cbytes,cpoints); +} + +// ANSI operators +uString & uString::operator=(const char *Src) { + aString tmp=Src; + buffer=CHARTOUTF8((const Uint8*)tmp.c_str(),cbytes,cpoints); + return *this; +} + +uString & uString::operator=(const char &Src) { + Uint8 tmp[2]={Src,0}; + buffer=CHARTOUTF8((const Uint8*)tmp,cbytes,cpoints); + return *this; +} + +uString & uString::operator=(const uString &Src) { + cbytes=Src.cbytes; + cpoints=Src.cpoints; + buffer=Src.buffer; + return *this; +} + +uString & uString::operator=(const aString &Src) { + buffer=CHARTOUTF8((const Uint8*)Src.c_str(),cbytes,cpoints); + return *this; +} + +uString & uString::operator+=(const char *Src) { + Uint32 tbytes,tpoints; + buffer+=CHARTOUTF8((Uint8*)Src,tbytes,tpoints); + cbytes+=tbytes; + cpoints+=tpoints; + return *this; +} + +uString & uString::operator+=(const char &Src) { + Uint32 tbytes,tpoints; + Uint8 tmp[2]={Src,0}; + buffer+=CHARTOUTF8(tmp,tbytes,tpoints); + cbytes+=tbytes; + cpoints+=tpoints; + return *this; +} + +uString & uString::operator+=(const aString &Src) { + Uint32 tbytes,tpoints; + buffer+=CHARTOUTF8((Uint8*)Src.c_str(),tbytes,tpoints); + cbytes+=tbytes; + cpoints+=tpoints; + return *this; +} + +uString & uString::operator+=(const uString &Src) { + buffer+=Src.buffer; + cbytes+=Src.cbytes; + cpoints+=Src.cpoints; + return *this; +} + +uString uString::operator+(const char *Src) { + aString temporary=buffer; + temporary+=Src; + return temporary.c_str(); +} + +uString uString::operator+(const char &Src) { + Uint8 tmp[2]={Src,0}; + uString temporary=buffer; + temporary+=(char*)tmp; + return temporary.c_str(); +} + +uString uString::operator+(const uString &Src) { + aString temporary=buffer; + temporary+=Src.buffer; + return temporary.c_str(); +} + +bool uString::operator==(const char *Src) { + return *this==uString(Src); +} + +bool uString::operator==(const char &Src) { + return *this==uString(Src); +} + +bool uString::operator==(const aString &Src) { + return *this==uString(Src); +} + +bool uString::operator==(const uString &Src) { + return buffer==Src.buffer; +} + +bool uString::operator!=(const char *Src) { + return *this!=uString(Src); +} + +bool uString::operator!=(const char &Src) { + return *this!=uString(Src); +} + +bool uString::operator!=(const aString &Src) { + return *this!=uString(Src); +} + +bool uString::operator!=(const uString &Src) { + return !(*this==Src); +} + + + +#ifdef VILE_BUILD_UNICODE +// UNICODE constructors +uString::uString(const wString *Src){ + buffer=WIDETOUTF8(Src->c_str(),cbytes,cpoints); +} + +uString::uString(const wchar_t *Src){ + buffer=WIDETOUTF8(Src,cbytes,cpoints); +} + +uString::uString(const wchar_t &Src){ + wString tmp; + tmp+=Src; + buffer=WIDETOUTF8(tmp.c_str(),cbytes,cpoints); +} + +uString::uString(const wString &Src){ + buffer=WIDETOUTF8(Src.c_str(),cbytes,cpoints); +} + +// UNICODE operators +uString & uString::operator=(const wchar_t *Src) { + buffer=WIDETOUTF8(Src,cbytes,cpoints); + return *this; +} + +uString & uString::operator=(const wchar_t &Src) { + wString tmp; + tmp+=Src; + buffer=WIDETOUTF8(tmp.c_str(),cbytes,cpoints); + return *this; +} + +uString & uString::operator=(const wString &Src) { + buffer=WIDETOUTF8(Src.c_str(),cbytes,cpoints); + return *this; +} + +uString & uString::operator+=(const wchar_t *Src) { + Uint32 tbytes,tpoints; + buffer+=WIDETOUTF8(Src,tbytes,tpoints); + cbytes+=tbytes; + cpoints+=tpoints; + return *this; +} + +uString & uString::operator+=(const wchar_t &Src) { + Uint32 tbytes,tpoints; + wString tmp; + tmp+=Src; + buffer+=WIDETOUTF8(tmp.c_str(),tbytes,tpoints); + cbytes+=tbytes; + cpoints+=tpoints; + return *this; +} + +uString & uString::operator+=(const wString &Src) { + Uint32 tbytes,tpoints; + buffer+=WIDETOUTF8(Src.c_str(),tbytes,tpoints); + cbytes+=tbytes; + cpoints+=tpoints; + return *this; +} + +uString uString::operator+(const wchar_t *Src) { + uString temporary=buffer; + temporary+=Src; + return temporary.c_str(); +} + +uString uString::operator+(const wchar_t &Src) { + wchar_t src[8]={0}; + src[0]=Src; + uString temporary=buffer; + temporary+=src; + return temporary.c_str(); +} + +bool uString::operator==(const wchar_t *Src) { + return *this==uString(Src); +} + +bool uString::operator==(const wchar_t &Src) { + return *this==uString(Src); +} + +bool uString::operator==(const wString &Src) { + return *this==uString(Src); +} + +bool uString::operator!=(const wchar_t *Src) { + return *this!=uString(Src); +} + +bool uString::operator!=(const wchar_t &Src) { + return *this!=uString(Src); +} + +bool uString::operator!=(const wString &Src) { + return *this!=uString(Src); +} + +#endif + + +/*! \brief Find first occurrance of Text + * \param Text Text to search for + * \param Start Start index + * \param Length Maximum number of characters to search for + * \return Starting index of found text or negative if failed + */ +int uString::find_first(const uString &Text,int Start,int Length) const{ + int li=points(); + int le=Text.points(); + if(Start
  • 0){ + const char *bi=buffer.c_str(); + const char *be=Text.buffer.c_str(); + li-=Start; + Length=EDL_MIN(Length,li); + if(Length<0){ + Length=li; + } + if(Start>0){ + utf8::unchecked::advance(bi,Start); + } + int matched=0; + for(int i=0;i0){ + // Find boundries and buffer pointers + const char *bi=buffer.c_str(); + const char *be=Text.buffer.c_str(); + li-=Start; + if(Length<0){ + Length=li; + } + + // Search for start of word + utf8::unchecked::advance(bi,li); + Length=EDL_MIN(Length,li); + for(int i=0;i=count){ + // Out of boundry request + } + else{ + // Extract substring + count-=Start; + Length=EDL_MIN(count,Length); + for(int i=0;iu2){ + return 1; + } + if(u10){ + utf8::unchecked::advance(bp,Index); + } + char u[5]={0,0,0,0,0}; + utf8::unchecked::append(utf8::unchecked::next(bp),u); + retval=u; + } + return retval; + } +} + +/*! \brief Counts number of characters in the string + * \return Number of characters in the string + */ +unsigned int uString::length() const { + return cpoints; +} + +/*! \brief Counts number of bytes in the string + * \return Number of bytes in the string + */ +unsigned int uString::bytes() const { + return cbytes; +} + +/*! \brief Counts number of characters in the string + * \return Number of characters in the string + */ +unsigned int uString::points() const { + return cpoints; +} + +/*! \brief Counts number of characters in a utf string + * \return Number of characters in the string + */ +unsigned int uString::points(const aString Text) const { + if(Text.length()){ + aString text=Text; + aString::iterator end_it=utf8::find_invalid(text.begin(),text.end()); +#if VILE_UNICODE_SAFE + return utf8::distance(text.begin(),end_it); +#else + return utf8::unchecked::distance(text.begin(),end_it); +#endif + } + else{ + return 0; + } +} + +/*! \brief Extracts UTF8 encoded text string + * \return UTF8 encoded text string + */ +const char *uString::c_str() const { + return buffer.c_str(); +} + +/*! \brief Extracts text string and converts it to UTF16 + * \return UTF16 encoded text string + */ +const wchar_t *uString::c_wstr() { + const char *in=buffer.c_str(); +#ifdef VILE_ARCH_MICROSOFT + std::vector out; + utf8::unchecked::utf8to16(in,in+buffer.length(),back_inserter(out)); +#else + std::vector out; + utf8::unchecked::utf8to32(in,in+buffer.length(),back_inserter(out)); +#endif + wbuffer=std::wstring(out.begin(),out.end()); + return wbuffer.c_str(); +} + + +/*! \brief Gets ordinal of first character + * \return 32 Unicode codepoint + */ +Uint32 uString::to_code() const{ + if(points()){ + const char *ptr=buffer.c_str(); + return utf8::unchecked::next(ptr); + } + else{ + return 0; + } +} + +uString uString::to_lower() const{ + //! \todo UNICODE compliant case-conversion + uString tmp; + uString retval; + int count=points(); + for(int i=0;i double conversion + char *endptr,*str; + str=(char*)buffer.c_str(); + double retval=strtod(str,&endptr); + if(endptr==str){ + LogVerbose("Failed to convert double: %s",str); + } + return retval; +} + +int uString::to_int(int Base) const{ + //! \todo UNICODE compliant string -> int conversion + char *endptr,*str; + str=(char*)buffer.c_str(); + Uint32 retval=strtol(str,&endptr,Base); + if(endptr==str){ + LogVerbose("Failed to convert integer: %s",str); + } + return retval; +} + +aString uString::UTF32TOUTF8(const Uint32 *Src,const unsigned int Length){ + aString retval; + if(Length>0 && Length<16*1024){ + std::vector out; +#if VILE_UNICODE_SAFE + utf8::utf32to8(Src,Src+Length,back_inserter(out)); +#else + utf8::unchecked::utf32to8(Src,Src+Length,back_inserter(out)); +#endif + retval=aString(out.begin(),out.end()); + } + return retval; +} + + +aString uString::UTF16TOUTF8(const Uint16 *Src,const unsigned int Length){ + aString retval; + if(Length>0 && Length<16*1024){ + std::vector out; +#if VILE_UNICODE_SAFE + utf8::utf16to8(Src,Src+Length,back_inserter(out)); +#else + utf8::unchecked::utf16to8(Src,Src+Length,back_inserter(out)); +#endif + retval=aString(out.begin(),out.end()); + } + return retval; +} + +aString uString::UTF8TOUTF8(const Uint8 *Src,const unsigned int Length){ + aString retval; + if(Length>0 && Length<16*1024){ + aString in=std::string((char*)Src,Length); + std::string::iterator end_it=utf8::find_invalid(in.begin(),in.end()); + retval=aString(in.begin(),end_it); + if(end_it!=in.end()) { + LogError("Invalid UTF8 data found"); + uString dumpin,dumpout; + for(unsigned int i=0;i +#include +#include +#include + +#define VILE_UNICODE_SAFE 0 + +// Native handlers +#define aString std::string +#define wString std::wstring + +class uString { + protected: + // Internal UTF8 handling + aString buffer; + wString wbuffer; + aString CHARTOUTF8(const Uint8 *Src,Uint32 &Bytes,Uint32 &Points); + aString WIDETOUTF8(const wchar_t *Src,Uint32 &Bytes,Uint32 &Points); + + // Optimalizations + unsigned int cbytes; + unsigned int cpoints; + public: + // ANSI compliant Constructors and operators + uString(); + uString(const aString *Src); + uString(const char *Src); + uString(const aString &Src); + uString(const uString &Src); + uString(const char &Src); + uString & operator=(const uString &Src); + uString & operator=(const aString &Src); + uString & operator=(const char *Src); + uString & operator=(const char &Src); + uString & operator+=(const uString &Src); + uString & operator+=(const aString &Src); + uString & operator+=(const char *Src); + uString & operator+=(const char &Src); + uString operator+(const uString &Src); + uString operator+(const aString &Src); + uString operator+(const char *Src); + uString operator+(const char &Src); + bool operator==(const uString &Src); + bool operator==(const aString &Src); + bool operator==(const char *Src); + bool operator==(const char &Src); + bool operator!=(const uString &Src); + bool operator!=(const aString &Src); + bool operator!=(const char *Src); + bool operator!=(const char &Src); + +#ifdef VILE_BUILD_UNICODE + // Unicode compliant set of constructors and operators + uString(const wString *Src); + uString(const wchar_t *Src); + uString(const wString &Src); + uString(const wchar_t &Src); + uString & operator=(const wString &Src); + uString & operator=(const wchar_t *Src); + uString & operator=(const wchar_t &Src); + uString & operator+=(const wchar_t *Src); + uString & operator+=(const wString &Src); + uString & operator+=(const wchar_t &Src); + uString operator+(const wString &Src); + uString operator+(const wchar_t *Src); + uString operator+(const wchar_t &Src); + bool operator==(const wString &Src); + bool operator==(const wchar_t *Src); + bool operator==(const wchar_t &Src); + bool operator!=(const wString &Src); + bool operator!=(const wchar_t *Src); + bool operator!=(const wchar_t &Src); +#endif + + // std::string compability + uString operator[](const unsigned int Index) const; + uString substr(int Start,int Length=-1) const; + int compare(const uString &str) const; + const char *c_str() const; + const wchar_t *c_wstr(); + unsigned int length() const; + unsigned int bytes() const; + unsigned int points() const; + unsigned int points(const aString) const; + + // String utilities + int to_int(int Base=10) const; + double to_double() const; + uString to_lower() const; + uString to_upper() const; + Uint32 to_code() const; + int find_first(const uString &Text,int Start=0,int Length=-1) const; + int find_last(const uString &Text,int Start=0,int Length=-1) const; + + // Encoding/conversion API + aString EXTERNTOUTF8(const Uint8 *Src,const unsigned int Length); + aString UTF8TOUTF8(const Uint8 *Src,const unsigned int Length); + aString UTF16TOUTF8(const Uint16 *Src,const unsigned int Length); + aString UTF32TOUTF8(const Uint32 *Src,const unsigned int Length); + +}; + +#endif + diff --git a/engines/vileVN/configure.engine b/engines/vileVN/configure.engine new file mode 100644 index 0000000000..579fc3cda4 --- /dev/null +++ b/engines/vileVN/configure.engine @@ -0,0 +1,3 @@ +# This file is included from the main "configure" script +# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps] +add_engine vileVN "VileVN" wip "" "" "highres 16bit" \ No newline at end of file diff --git a/engines/vileVN/cware/cware.cpp b/engines/vileVN/cware/cware.cpp new file mode 100644 index 0000000000..185426b889 --- /dev/null +++ b/engines/vileVN/cware/cware.cpp @@ -0,0 +1,778 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "cware.h" + + +EngineCWare::EngineCWare(int Width,int Height) : EngineVN(Width,Height){ + // Set defaults + scriptbuffer=0; + scriptlength=0; + scriptindex=0; + saveindex=0; + state=CWARESTATE_NORMAL; + + // Load gui interface + EDL_SETRECT(background,32,8,576,376); + display=new Widget(0,0,640,480); + textview=new Textview(this); + selection=new Selection(this); + map=new CWareMap(this); + AddWidget(display,VL_BACKGROUND); + AddWidget(textview,VL_TEXTVIEW); + AddWidget(selection,VL_CHOICES); + AddWidget(map,VL_CHOICES); + + // Preset widget configuration + map->SetVisible(false); +} + +EngineCWare::~EngineCWare(){ + if(scriptbuffer){ + delete [] scriptbuffer; + } +} + +/*! \brief Pauses the game + */ +void EngineCWare::Pause(){ + if(Running()){ + scriptindex=saveindex; + state=CWARESTATE_PAUSED; + } +} + +/*! \brief Unpauses the game + */ +void EngineCWare::Resume(){ + if(state==CWARESTATE_PAUSED){ + state=CWARESTATE_NORMAL; + } +} + +/*! \brief Tells wether a script is loaded + * \returns True if a script is properly loaded + */ +bool EngineCWare::Running(){ + return scriptbuffer; +} + +/*! \brief Stops the engine and flushes any script data + */ +void EngineCWare::Stop(){ + if(scriptbuffer){ + delete [] scriptbuffer; + } + scriptbuffer=0; + scriptlength=0; + scriptindex=0; +} + +/*! \brief Jumps to an absolute position in the current script + * \param Byteposition in the script + * + * This method is typically used from the CWareMap class to resume the + * game from the point the user selects. Note that this involves asserting + * the processing state of the engine. + */ +bool EngineCWare::Jump(unsigned int Position){ + if(PositionSeek(0,SEEK_END); + if(tlength>(int)0){ + // Replace blob + blob->Seek(0,SEEK_SET); + unsigned char *tbuffer=new unsigned char[tlength]; + if(blob->Read(tbuffer,tlength)>(int)0){ + // Register new script data + if(scriptbuffer){ + delete [] scriptbuffer; + } + scriptname=Script; + scriptbuffer=tbuffer; + scriptlength=tlength; + scriptindex=0; + saveindex=0; + retval=true; + + // Force new start + textview->ClearText(); + state=CWARESTATE_NORMAL; + } + } + delete blob; + } + return retval; +} + +bool EngineCWare::EventLoad(int Index){ + bool retval=false; + Savegame *load=new Savegame(NativeID(),Index); + if(load->Read()){ + // Clear existing data + selection->SetVisible(false); + EventNew(); + + // Load script data + load->LoadString("scriptname",&scriptname); + LoadCWareScript(scriptname); + load->LoadVector("variables",&vars); + load->LoadUint32("saveindex",(Uint32*)&saveindex); + load->LoadUint32("saveindex",(Uint32*)&scriptindex); + state=CWARESTATE_NORMAL; + + // Load graphics + SDL_Surface *tmps; + if(load->LoadSurface("screen-display",&tmps)){ + display->Blit(tmps); + SDL_FreeSurface(tmps); + } + + // Close dialog + retval=true; + } + delete load; + return retval; +} + +bool EngineCWare::EventSave(int Index){ + // Gather date string + uString date=EDL_DateString(EDL_UnixTime()); + uString time=EDL_TimeString(EDL_UnixTime()); + uString datetime=date+uString(" ")+time; + + // Store script data + Savegame *save=new Savegame(NativeID(),Index); + save->SaveString("scriptname",scriptname); + save->SaveUint32("saveindex",saveindex); + save->SaveVector("variables",&vars); + save->SaveString("savedate",datetime); + save->SaveString("savemsg",GetSavename()); + + // Store graphics + SDL_Surface *screen=EDL_CreateSurface(NativeWidth(),NativeHeight()); + Paint(screen,VL_BACKGROUND); + save->SaveSurface("screen-thumb",screen,96,72); + save->SaveSurface("screen-display",screen); + SDL_FreeSurface(screen); + + // Close dialogs + save->Write(); + delete save; + return true; +} + +void EngineCWare::EventGameDialog(VN_DIALOGS Dialog){ + if(Dialog==VD_EXTRAS){ + // Stop game features + textview->ClearText(); + StopMusic(); + StopSound(); + Pause(); + } + else{ + EngineVN::EventGameDialog(Dialog); + } +} + +void EngineCWare::EventSelect(int Selection){ + if((unsigned int)SelectionSetVisible(false); + } +} + +bool EngineCWare::EventGameTick(){ + if(state==CWARESTATE_WAITCLICK){ + bool skip=keyok || keyctrl() || GetSkipmode(); + if(skip && textview->GetRemainingText()){ + textview->CompleteText(); + keyok=false; + } + else if(skip){ + StopSound(VA_VOICES); + state=CWARESTATE_NORMAL; + textview->ClearText(); + keyok=false; + } + } + return !(state==CWARESTATE_NORMAL && !textview->GetRemainingText()); +} + +bool EngineCWare::EventGameProcess(){ + bool retval=true; + if(scriptbuffer && scriptindexPrintText(text); + return true; +} + +bool EngineCWare::OP0001(){ + Uint32 index=GETDWORD(scriptbuffer+scriptindex); + scriptindex+=4; + aString text; + while(scriptbuffer[scriptindex]){ + if(scriptbuffer[scriptindex]=='@'){ + scriptindex++; + text+="\""; + } + else{ + text+=scriptbuffer[scriptindex++]; + } + } + scriptindex++; + int selindex=selection->GetWidgetCount(); + SDL_Rect r=selection->GetPosition(); + r.h=20; + r.y+=r.h*selindex; + selection->SetText(text,r,index); + return false; +} + +bool EngineCWare::OP0002(){ + scriptindex=GETDWORD(scriptbuffer+scriptindex); + return false; +} + +/*! Sets multiple variables to the same value + */ +bool EngineCWare::OP0003(){ + Uint16 start=GETWORD(scriptbuffer+scriptindex+0); + Uint16 end=GETWORD(scriptbuffer+scriptindex+2); + Uint16 value=GETWORD(scriptbuffer+scriptindex+4); + scriptindex+=6; + for(int i=start;i<=end;i++){ + vars.SetUint16(i,value); + } + return false; +} + +/*! Sets a variable + */ +bool EngineCWare::OP0004(){ + Uint16 index=GETWORD(scriptbuffer+scriptindex+0); + Uint8 op=GETBYTE(scriptbuffer+scriptindex+2); + Uint16 v2=GETWORD(scriptbuffer+scriptindex+3); + scriptindex+=5; + + // Calculate value + Uint16 v1=vars.GetUint16(index); + if(op=='=') v1=v2; + else if(op=='+') v1+=v2; + else if(op=='-') v1-=v2; + else{ + LogError("Unknown operator: %c",op); + } + + // Write back value + vars.SetUint16(index,v1); + return false; +} + +/*! \brief Clear existing options + */ +bool EngineCWare::OP0006(){ + selection->SetVisible(false); + selection->Clear(); + return false; +} + +/*! \brief Show choices + */ +bool EngineCWare::OP0007(){ + if(selection->GetWidgetCount()){ + selection->SetVisible(true); + state=CWARESTATE_CHOICE; + } + else{ + LogError("Cannot display choices"); + } + return true; +} + +/*! \brief Redisplay choices + */ +bool EngineCWare::OP000A(){ + if(selection->GetWidgetCount()){ + selection->SetVisible(true); + state=CWARESTATE_CHOICE; + } + else{ + LogError("Cannot redisplay old choices"); + } + return true; +} + +bool EngineCWare::OP0010(){ + Uint16 index=GETWORD(scriptbuffer+scriptindex+0); + Uint8 op=GETBYTE(scriptbuffer+scriptindex+2); + Uint16 v2=GETWORD(scriptbuffer+scriptindex+3); + Uint32 pos=GETDWORD(scriptbuffer+scriptindex+5); + scriptindex+=9; + + // Calculate value + Uint16 v1=vars.GetUint16(index); + bool result=false; + if(op=='=') result=(v1==v2); + else if(op=='}') result=(v1>v2); + else if(op=='{') result=(v1Blend(surface,0,&background); + SDL_FreeSurface(surface); + SDL_FreeSurface(overlay); + UnlockCG(name); + } + else{ + LogError("Failed to load overlay: %s",name.c_str()); + } + return false; +} + +/*! Load script + */ +bool EngineCWare::OP0018(){ + aString name; + while(scriptbuffer[scriptindex]){ + name+=scriptbuffer[scriptindex++]; + } + scriptindex++; + if(!LoadCWareScript(name)){ + LogError("Failed to load %s",name.c_str()); + } + return true; +} + +bool EngineCWare::OP0019(){ + EventGameDialog(VD_TITLE); + return true; +} + +/*! Fade out background to black + */ +bool EngineCWare::OP001E(){ + AddAnimation(new FadeBlack(background,1000)); + return true; +} + +/*! Fade out background to white + */ +bool EngineCWare::OP001F(){ + AddAnimation(new FadeWhite(background,1000)); + return true; +} + +/*! Start background music + */ +bool EngineCWare::OP0026(){ + aString bgm; + while(scriptbuffer[scriptindex]){ + bgm+=scriptbuffer[scriptindex++]; + } + scriptindex++; + PlayMusic(bgm); + return false; +} + +/*! Stop background music + */ +bool EngineCWare::OP0028(){ + StopMusic(); + return true; +} + +/*! Start voice + */ +bool EngineCWare::OP002B(){ + aString sound; + while(scriptbuffer[scriptindex]){ + sound+=scriptbuffer[scriptindex++]; + } + scriptindex++; + PlaySound(sound,VA_VOICES); + return false; +} + +/*! Set screen clipping (Which is handled internally in ViLE) + */ +bool EngineCWare::OP0030(){ + //Uint16 x1=GETWORD(scriptbuffer+scriptindex+0); + //Uint16 y1=GETWORD(scriptbuffer+scriptindex+2); + //Uint16 x2=GETWORD(scriptbuffer+scriptindex+4); + //Uint16 y2=GETWORD(scriptbuffer+scriptindex+6); + scriptindex+=8; + return false; +} + +/*! Start sound + */ +bool EngineCWare::OP0035(){ + aString sound; + while(scriptbuffer[scriptindex]){ + sound+=scriptbuffer[scriptindex++]; + } + scriptindex++; + PlaySound(sound,VA_SOUNDS); + return false; +} + +/*! Stop sound effect + */ +bool EngineCWare::OP0036(){ + StopSound(VA_SOUNDS); + return true; +} + +/*! Configures/loads graphics for the map + */ +bool EngineCWare::OP0037(){ + // Parse image names + aString name1; + aString name2; + while(scriptbuffer[scriptindex]){ + name1+=scriptbuffer[scriptindex++]; + } + scriptindex++; + while(scriptbuffer[scriptindex]){ + name2+=scriptbuffer[scriptindex++]; + } + scriptindex++; + + // Replace current images + map->SetBackground(name1); + map->SetForeground(name2); + return false; +} + +/*! Flush locations from the map + */ +bool EngineCWare::OP0038(){ + map->Flush(); + return false; +} + +/*! Add locations to the map + */ +bool EngineCWare::OP0040(){ + Uint32 p=GETDWORD(scriptbuffer+scriptindex+0); + Uint16 x1=GETWORD(scriptbuffer+scriptindex+4); + Uint16 y1=GETWORD(scriptbuffer+scriptindex+6); + Uint16 x2=GETWORD(scriptbuffer+scriptindex+8); + Uint16 y2=GETWORD(scriptbuffer+scriptindex+10); + map->AddLocation(x1,y1,x2,y2,p); + scriptindex+=12; + return false; +} + +/*! Show map + */ +bool EngineCWare::OP0041(){ + map->SetVisible(true); + state=CWARESTATE_CHOICE; + return true; +} + +/*! Load foreground image + */ +bool EngineCWare::OP0046(){ + aString name; + while(scriptbuffer[scriptindex]){ + name+=scriptbuffer[scriptindex++]; + } + scriptindex++; + SDL_Surface *tmps=LoadImage(name); + if(tmps){ + display->Blit(tmps); + SDL_FreeSurface(tmps); + } + return false; +} + +/*! Load background image + */ +bool EngineCWare::OP0047(){ + aString name; + while(scriptbuffer[scriptindex]){ + name+=scriptbuffer[scriptindex++]; + } + scriptindex++; + SDL_Surface *surface=LoadImage(name); + if(surface){ + display->Blit(surface,0,&background); + SDL_FreeSurface(surface); + UnlockCG(name); + } + return false; +} + +/*! \brief Repaints clipped screen rect (Not used in ViLE) + */ +bool EngineCWare::OP004A(){ + //Uint16 arg=GETWORD(scriptbuffer+scriptindex+0); + scriptindex+=2; + return true; +} + +/*! Load single character image + */ +bool EngineCWare::OP004B(){ + // Get name of image and mask + aString name; + while(scriptbuffer[scriptindex]){ + name+=scriptbuffer[scriptindex++]; + } + scriptindex++; + uString mname=name; + for(unsigned int i=0;iw)/2; + int y=(background.y+background.h)-surface->h; + SDL_Rect t={x,y,surface->w,surface->h}; + display->Blend(surface,0,&t); + SDL_FreeSurface(surface); + SDL_FreeSurface(mask); + SDL_FreeSurface(cg); + } + else if(cg){ + LogError("Failed to load character mask: %s",mname.c_str()); + SDL_FreeSurface(cg); + } + else{ + LogError("Failed to load character image: %s",name.c_str()); + } + return false; +} + +/*! Load two character images + */ +bool EngineCWare::OP004C(){ + // Parse names for first character image set + aString name1; + while(scriptbuffer[scriptindex]){ + name1+=scriptbuffer[scriptindex++]; + } + scriptindex++; + aString mname1=name1; + for(unsigned int i=0;iw)/2; + int y=(background.y+background.h)-surface->h; + SDL_Rect t={x,y,surface->w,surface->h}; + display->Blend(surface,0,&t); + SDL_FreeSurface(surface); + SDL_FreeSurface(mask); + SDL_FreeSurface(cg); + } + else if(cg){ + LogError("Failed to load character mask: %s",mname1.c_str()); + SDL_FreeSurface(cg); + } + else{ + LogError("Failed to load character image: %s",name1.c_str()); + } + + // Load second as foreground + cg=LoadImage(name2); + mask=LoadImage(mname2); + if(cg && mask){ + SDL_Surface *surface=EDL_MaskSurface(cg,mask,0); + int x=(((NativeWidth()/2)-surface->w)/2)+(NativeWidth()/2); + int y=(background.y+background.h)-surface->h; + SDL_Rect t={x,y,surface->w,surface->h}; + display->Blend(surface,0,&t); + SDL_FreeSurface(surface); + SDL_FreeSurface(mask); + SDL_FreeSurface(cg); + } + else if(cg){ + LogError("Failed to load character mask: %s",mname1.c_str()); + SDL_FreeSurface(cg); + } + else{ + LogError("Failed to load character image: %s",name1.c_str()); + } + return false; +} + +bool EngineCWare::OP004D(){ + LogTest("ANIMATE BACKGROUND"); + return false; +} + +bool EngineCWare::OP004E(){ + LogTest("SCROLL DOWN"); + return false; +} + +bool EngineCWare::OP004F(){ + LogTest("SCROLL UP"); + return false; +} + +bool EngineCWare::OP0050(){ + aString savename; + while(scriptbuffer[scriptindex]){ + savename+=scriptbuffer[scriptindex++]; + } + scriptindex++; + SetSavename(savename); + return false; +} + diff --git a/engines/vileVN/cware/cware.h b/engines/vileVN/cware/cware.h new file mode 100644 index 0000000000..f3262b8c28 --- /dev/null +++ b/engines/vileVN/cware/cware.h @@ -0,0 +1,98 @@ +/*! \class EngineCWare + * \brief CWare game engine + * + * CWare uses a simple word parser + */ +#ifndef _CWARE_H_ +#define _CWARE_H_ + +#include "../engine/evn.h" +#include "cwaremap.h" + +#define GETBYTE(B) ((B)[0]) +#define GETWORD(B) ((B)[0]|((B)[1]<<8)) +#define GETDWORD(B) ((B)[0]|((B)[1]<<8)|((B)[2]<<16)|((B)[3]<<24)) + +enum CWARESTATES { + CWARESTATE_NORMAL, //!< Process input script + CWARESTATE_CHOICE, //!< Wait for user to click a selection + CWARESTATE_WAITCLICK, //!< Wait for user to click + CWARESTATE_PAUSED //!< Show Extras/CG +}; + +class EngineCWare : public EngineVN { + private: + // Script data + uString scriptname; //!< Name of current script + Uint8 *scriptbuffer; //!< Script data + unsigned int scriptlength; //!< Length of script data + unsigned int scriptindex; //!< Index of binary script buffer + unsigned int saveindex; //!< Position for savegame + DVector vars; //!< Holds values + CWARESTATES state; //!< Current state + + // Opcode handlers + bool OP0000(); //!< Print text + bool OP0001(); //!< Add option + bool OP0002(); //!< Jump to position + bool OP0003(); //!< Copies a value to a bulk of variables + bool OP0004(); //!< Copies a value to a variable + bool OP0006(); //!< Flushes choices + bool OP0007(); //!< Show options + bool OP000A(); //!< Show again + bool OP0010(); //!< Jump if NOT + bool OP0011(); //!< Wait (milliseconds) + bool OP0014(); //!< Repaint display + bool OP0016(); //!< Load overlay image + bool OP0018(); //!< Load script + bool OP0019(); //!< Game end + bool OP001E(); //!< Fade to black + bool OP001F(); //!< Fade to white + bool OP0026(); //!< Start music + bool OP0028(); //!< Stop music + bool OP002B(); //!< Play voice + bool OP0030(); //!< Set clipping + bool OP0035(); //!< Play sound + bool OP0036(); //!< Stop sound + bool OP0037(); //!< Map overlay background + bool OP0038(); //!< Clear map overlay + bool OP0040(); //!< Add map overlay + bool OP0041(); //!< Show map overlay + bool OP0046(); //!< Load foreground image + bool OP0047(); //!< Load background image + bool OP004A(); //!< Repaint clipped area + bool OP004B(); //!< Load character image + bool OP004C(); //!< Load two character images + bool OP004D(); + bool OP004E(); //!< Scroll down + bool OP004F(); //!< Scroll up + bool OP0050(); //!< Set title for savegame + protected: + SDL_Rect background; //!< Defines display rect + Widget *display; //!< Widget for showing base graphics + Textview *textview; //!< Textview display + Selection *selection; //!< Simple text choices + CWareMap *map; //!< Map object + public: + EngineCWare(int Width,int Height); + ~EngineCWare(); + + // Game interface + bool LoadCWareScript(uString Script); + bool Jump(unsigned int Position); + bool Running(); + void Stop(); + void Pause(); + void Resume(); + + // Eventhandlers + virtual bool EventGameTick(); + virtual bool EventGameProcess(); + virtual bool EventLoad(int Index); + virtual bool EventSave(int Index); + virtual void EventSelect(int Selection); + virtual void EventGameDialog(VN_DIALOGS Dialog); +}; + +#endif + diff --git a/engines/vileVN/cware/cwaremap.cpp b/engines/vileVN/cware/cwaremap.cpp new file mode 100644 index 0000000000..3f3886b97b --- /dev/null +++ b/engines/vileVN/cware/cwaremap.cpp @@ -0,0 +1,129 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "cwaremap.h" +#include "cware.h" + +CWareMap::CWareMap(EngineCWare *Engine) : DialogBase(Engine,false){ + Resize(576,376); + Move(32,8); + bg=0; + fg=0; +} + +CWareMap::~CWareMap(){ + if(bg){ + SDL_FreeSurface(bg); + } + if(fg){ + SDL_FreeSurface(fg); + } +} + +bool CWareMap::InputOk(Widget *Object){ + bool retval=false; + if(Object && Object->GetTag()>0){ + ((EngineCWare*)engine)->Jump(Object->GetTag()); + SetVisible(false); + retval=true; + } + return retval; +} + +/*! \brief Flush all items + */ +void CWareMap::Flush(){ + DestroyWidgets(); + istring=""; +} + +/*! \brief Loads old mapdata from a string + * \param MapSettings String to load (Usually from SaveMap()) + * \returns True if map data was valid + */ +bool CWareMap::LoadMap(uString MapSettings){ + return false; +} + +/*! \brief Generates a string that can be used to reload current map + * \returns Map savestring + */ +uString CWareMap::SaveMap(){ + uString retval=bgstring; + retval+=":"; + retval+=fgstring; + retval+=istring; + return retval; +} + +/*! \brief Adds a location to the map + * \param X1 Screen coordinate + * \param Y1 Screen coordinate + * \param X2 Screen coordinate + * \param Y2 Screen coordinate + * \param Position Jump position for this item + */ +bool CWareMap::AddLocation(int X1,int Y1,int X2,int Y2,unsigned int Position){ + if(bg && fg){ + // Create button + SDL_Rect r={X1,Y1,X2-X1,Y2-Y1}; + BitmapButton *button=new BitmapButton(r); + button->SetState(WS_NORMAL,bg,&r); + button->SetState(WS_HOVER,fg,&r); + button->Move(r.x+32,r.y+8); + button->SetTag(Position); + AddWidget(button); + + // Add item to savestring + istring+=EDL_Format(":%d:%d:%d:%d:%u",X1,Y1,X2,Y2,Position); + } + return bg && fg; +} + +/*! \brief Registers an image for the background image + * \param Name Name of the image resource + * \returns True if a valid image resource was found + */ +bool CWareMap::SetBackground(uString Name){ + bool retval=false; + if(bg){ + SDL_FreeSurface(bg); + bg=0; + } + if((bg=engine->LoadImage(Name))){ + Blit(bg); + bgstring=Name; + retval=true; + } + return retval; +} + +/*! \brief Registers an image for the foreground overlay + * \param Name Name of the image resource + * \returns True if a valid image resource was found + */ +bool CWareMap::SetForeground(uString Name){ + bool retval=false; + if(fg){ + SDL_FreeSurface(fg); + fg=0; + } + if((fg=engine->LoadImage(Name))){ + fgstring=Name; + retval=true; + } + return retval; +} + diff --git a/engines/vileVN/cware/cwaremap.h b/engines/vileVN/cware/cwaremap.h new file mode 100644 index 0000000000..bc786bbe96 --- /dev/null +++ b/engines/vileVN/cware/cwaremap.h @@ -0,0 +1,36 @@ +/*! \class CWareMap + * \brief Manages graphical map selections for CWare games + */ + +#ifndef _CWAREMAP_H_ +#define _CWAREMAP_H_ + +#include "../dialogs/dlgbase.h" + +class EngineCWare; + +class CWareMap : public DialogBase { + private: + uString bgstring; //!< Stores name of background + uString fgstring; //!< Stores name of foreground + uString istring; //!< Stores items + SDL_Surface *bg; //!< Background surface + SDL_Surface *fg; //!< Foreground surface + virtual bool InputOk(Widget *Object); + public: + CWareMap(EngineCWare *Engine); + ~CWareMap(); + + // Map API + void Flush(); + bool SetBackground(uString Name); + bool SetForeground(uString Name); + bool AddLocation(int X1,int Y1,int X2,int Y2,unsigned int Position); + + // Support for loading and saving + bool LoadMap(uString MapSettings); + uString SaveMap(); +}; + +#endif + diff --git a/engines/vileVN/cware/dividead/divicg.cpp b/engines/vileVN/cware/dividead/divicg.cpp new file mode 100644 index 0000000000..9186b370b3 --- /dev/null +++ b/engines/vileVN/cware/dividead/divicg.cpp @@ -0,0 +1,162 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "divicg.h" +#include "dividead.h" + +DiviCG::DiviCG(DiviDead *Engine) : Hotspot(32,8,576,376) { + game=Engine; + loadpage(0); +} + +void DiviCG::loadpage(int Index){ + // Load images and staring index + overview=true; + pageindex=Index; + SDL_Surface *bgs=0; + SDL_Surface *fgs=0; + int sindex=0; + if(pageindex==0){ + bgs=game->LoadImage("cgmode_1"); + fgs=game->LoadImage("cgmode_a"); + } + else if(pageindex==1){ + bgs=game->LoadImage("cgmode_2"); + fgs=game->LoadImage("cgmode_b"); + sindex+=24-1; + } + else if(pageindex==2){ + bgs=game->LoadImage("cgmode_2"); + fgs=game->LoadImage("cgmode_c"); + sindex+=24+(23*1)-1; + } + else if(pageindex==3){ + bgs=game->LoadImage("cgmode_2"); + fgs=game->LoadImage("cgmode_d"); + sindex+=24+(23*2)-1; + } + else if(pageindex==4){ + bgs=game->LoadImage("cgmode_2"); + fgs=game->LoadImage("cgmode_e"); + sindex+=24+(23*3)-1; + } + else if(pageindex==5){ + bgs=game->LoadImage("cgmode_3"); + fgs=game->LoadImage("cgmode_f"); + sindex+=24+(23*4)-1; + } + + // Populate view + if(bgs){ + Blit(bgs); + if(fgs){ + bool flag; + uString name; + SDL_Rect r={0,0,107,70}; + int x=0,y=0; + for(int i=sindex;iMapCG(i,&flag,&name) && flag){ + r.x=(x*(r.w+5))+10; + r.y=(y*(r.h+4))+5; + Blit(fgs,&r,&r); + } + if(++x>4){ + x=0; + y++; + } + } + } + SDL_FreeSurface(bgs); + } + +} + +bool DiviCG::MouseLeftDown(int X,int Y){ + if(overview){ + // Calculate where the user clicked + int x=X-pos.x; + int y=Y-pos.y; + int w=pos.w/5; + int h=pos.h/5; + int hi=x/w; + int vi=y/h; + if(hi==0 && vi==0 && pageindex!=0){ + loadpage(pageindex-1); + } + else if(hi==4 && vi==4 && pageindex!=5){ + loadpage(pageindex+1); + } + else{ + int index=0; + bool flag=false; + uString name; + if(pageindex){ + index=24+(23*(pageindex-1))-1; + } + index+=hi+(vi*5); + if(game->MapCG(index,&flag,&name) && flag){ + SDL_Surface *surface=game->LoadImage(name); + if(surface){ + // Load widget and display surface + PopImage *pop=new PopImage(game); + pop->AddImage(surface,32,8); + game->AddWidget(pop,VL_OVERLAY); + SDL_FreeSurface(surface); + + // Add related resources + if(name=="i_20"){ + surface=game->LoadImage("i_20_"); + pop->AddImage(surface,32,8); + SDL_FreeSurface(surface); + } + if(name=="i_21"){ + surface=game->LoadImage("i_21a"); + pop->AddImage(surface,32,8); + SDL_FreeSurface(surface); + } + if(name=="i_26"){ + surface=game->LoadImage("i_26a"); + pop->AddImage(surface,32,8); + SDL_FreeSurface(surface); + } + if(name=="i_33"){ + surface=game->LoadImage("i_34"); + pop->AddImage(surface,32,8); + SDL_FreeSurface(surface); + surface=game->LoadImage("i_34a"); + pop->AddImage(surface,32,8); + SDL_FreeSurface(surface); + } + if(name=="i_46"){ + surface=game->LoadImage("i_46a"); + pop->AddImage(surface,32,8); + SDL_FreeSurface(surface); + } + if(name=="i_85"){ + surface=game->LoadImage("i_85a"); + pop->AddImage(surface,32,8); + SDL_FreeSurface(surface); + } + } + } + } + } + else{ + // Close currently shown image + loadpage(pageindex); + } + return true; +} + diff --git a/engines/vileVN/cware/dividead/divicg.h b/engines/vileVN/cware/dividead/divicg.h new file mode 100644 index 0000000000..ba2d87cc8d --- /dev/null +++ b/engines/vileVN/cware/dividead/divicg.h @@ -0,0 +1,20 @@ +#ifndef _DIVICG_H_ +#define _DIVICG_H_ + +#include "../../widgets/hotspot.h" + +class DiviDead; + +class DiviCG : public Hotspot { + private: + int pageindex; //!< Pageindex + bool overview; //!< Wether the overview is showing + DiviDead *game; //!< Holds pointer to engine + void loadpage(int Index); + public: + DiviCG(DiviDead *Engine); + virtual bool MouseLeftDown(int X,int Y); +}; + +#endif + diff --git a/engines/vileVN/cware/dividead/dividead.cpp b/engines/vileVN/cware/dividead/dividead.cpp new file mode 100644 index 0000000000..efba366f71 --- /dev/null +++ b/engines/vileVN/cware/dividead/dividead.cpp @@ -0,0 +1,295 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "dividead.h" + +DiviDead::DiviDead(uString Path) : EngineCWare(640,480) { + // Add resources + AddBGM(new ArchiveFiles(Path+"mid/*.mid")); + AddVoices(new ArchiveCWareDL1(Path+"wv.dl1")); + AddSE(new ArchiveCWareDL1(Path+"wv.dl1")); + AddScripts(new ArchiveCWareDL1(Path+"sg.dl1")); + AddImages(new ArchiveFiles(Path+"m_a1.bmp")); + AddImages(new ArchiveFiles(Path+"m_a2.bmp")); + AddImages(new ArchiveFiles(Path+"m_b1.bmp")); + AddImages(new ArchiveFiles(Path+"m_b2.bmp")); + AddImages(new ArchiveCWareDL1(Path+"sg.dl1")); + AddImages(new ArchiveCWareDL1(Path+"sg.dl1")); + AddVideo(new ArchiveFiles(Path+"cs_rogo.avi")); + AddVideo(new ArchiveFiles(Path+"open.avi")); + + // Add menu interface to background + main=0; + extra=0; + divigui=new DiviGUI(this); + AddWidget(divigui,VL_HOTSPOTS); + + // Configure textview + textview->SetTextPosition(0,0,440,70); + textview->MoveDialog(100,396); + textview->Resize(440,70); + + // Configure textview + //selection->Move(100,396); + //selection->Resize(440,70); + selection->Resize(640/3,480/3); + selection->Move(640/3,480/3); + selection->SetAlignment(HA_CENTER,VA_CENTER); + + // Map CG resources + int i=0; + RegisterCG(i++,"i_00"); + RegisterCG(i++,"i_01"); + RegisterCG(i++,"i_02"); + RegisterCG(i++,"i_03"); + RegisterCG(i++,"i_04"); + RegisterCG(i++,"i_06"); + RegisterCG(i++,"i_07"); + RegisterCG(i++,"i_08"); + RegisterCG(i++,"i_09"); + RegisterCG(i++,"i_10"); + RegisterCG(i++,"i_11"); + RegisterCG(i++,"i_12"); + RegisterCG(i++,"i_13"); + RegisterCG(i++,"i_14"); + RegisterCG(i++,"i_15"); + RegisterCG(i++,"i_16"); + RegisterCG(i++,"i_17"); + RegisterCG(i++,"i_18"); + RegisterCG(i++,"i_19"); + RegisterCG(i++,"i_20"); + RegisterCG(i++,"i_21"); + RegisterCG(i++,"i_22"); + RegisterCG(i++,"i_23"); + RegisterCG(i++,"i_24"); + RegisterCG(i++,"i_25"); + RegisterCG(i++,"i_26"); + RegisterCG(i++,"i_27"); + RegisterCG(i++,"i_28"); + RegisterCG(i++,"i_29"); + RegisterCG(i++,"i_30"); + RegisterCG(i++,"i_31"); + RegisterCG(i++,"i_32"); + RegisterCG(i++,"i_33"); + RegisterCG(i++,"i_35"); + RegisterCG(i++,"i_36"); + RegisterCG(i++,"i_37"); + RegisterCG(i++,"i_38"); + RegisterCG(i++,"i_39"); + RegisterCG(i++,"i_40"); + RegisterCG(i++,"i_41"); + RegisterCG(i++,"i_42"); + RegisterCG(i++,"i_43"); + RegisterCG(i++,"i_44"); + RegisterCG(i++,"i_45"); + RegisterCG(i++,"i_46"); + RegisterCG(i++,"i_47"); + RegisterCG(i++,"i_48"); + RegisterCG(i++,"i_49"); + RegisterCG(i++,"i_50"); + RegisterCG(i++,"i_51"); + RegisterCG(i++,"i_52"); + RegisterCG(i++,"i_53"); + RegisterCG(i++,"i_54"); + RegisterCG(i++,"i_55"); + RegisterCG(i++,"i_56"); + RegisterCG(i++,"i_57"); + RegisterCG(i++,"i_58"); + RegisterCG(i++,"i_59"); + RegisterCG(i++,"i_60"); + RegisterCG(i++,"i_61"); + RegisterCG(i++,"i_62"); + RegisterCG(i++,"i_63"); + RegisterCG(i++,"i_64"); + RegisterCG(i++,"i_65"); + RegisterCG(i++,"i_66"); + RegisterCG(i++,"i_67"); + RegisterCG(i++,"i_68"); + RegisterCG(i++,"i_69"); + RegisterCG(i++,"i_70"); + RegisterCG(i++,"i_71"); + RegisterCG(i++,"i_72"); + RegisterCG(i++,"i_73"); + RegisterCG(i++,"i_74"); + RegisterCG(i++,"i_75"); + RegisterCG(i++,"i_76"); + RegisterCG(i++,"i_77"); + RegisterCG(i++,"i_78"); + RegisterCG(i++,"i_79"); + RegisterCG(i++,"i_80"); + RegisterCG(i++,"i_81"); + RegisterCG(i++,"i_82"); + RegisterCG(i++,"i_83"); + RegisterCG(i++,"i_84"); + RegisterCG(i++,"i_85"); + RegisterCG(i++,"i_86"); + RegisterCG(i++,"i_88"); + RegisterCG(i++,"i_89"); + RegisterCG(i++,"i_90"); + RegisterCG(i++,"i_91"); + RegisterCG(i++,"i_92"); + RegisterCG(i++,"i_93"); + RegisterCG(i++,"i_95"); + RegisterCG(i++,"i_96"); + RegisterCG(i++,"i_97"); + RegisterCG(i++,"i_98"); + RegisterCG(i++,"i_99"); + RegisterCG(i++,"i_100"); + RegisterCG(i++,"i_101"); + RegisterCG(i++,"h_a0"); + RegisterCG(i++,"h_b0"); + RegisterCG(i++,"h_c0"); + RegisterCG(i++,"h_d0"); + RegisterCG(i++,"h_e0"); + RegisterCG(i++,"h_f0"); + RegisterCG(i++,"h_g0"); + RegisterCG(i++,"h_h0"); + + // Load videos + SDL_Rect client={0,0,640,480}; + AddAnimation(new FadeBlack(client,1000)); + QueueVideo("cs_rogo.avi"); + QueueVideo("open.avi"); + + // Show main menu + EventGameDialog(VD_TITLE); +} + +/*! \brief Toggles main menu visibilty + * \return True if main menu was shown + */ +bool DiviDead::ToggleMainmenu(){ + bool retval=false; + if(extra){ + DestroyWidget(extra); + extra=0; + } + if(main){ + DestroyWidget(main); + main=0; + } + else{ + SDL_Rect dummy={0,0,0,0}; + main=new DiviMenu(this); + main->SetText("NEW",dummy,DM_NEW); + if(Running()){ + main->SetText("SAVE",dummy,DM_SAVE); + } + main->SetText("LOAD",dummy,DM_LOAD); + main->SetText("CONFIG",dummy,DM_CONFIG); + main->SetText("EXIT",dummy,DM_EXIT); + main->Generate(); + AddWidget(main,VL_EXTRAS); + retval=true; + } + return retval; +} + +bool DiviDead::ToggleExtramenu(){ + bool retval=false; + if(main){ + DestroyWidget(main); + main=0; + } + if(extra){ + DestroyWidget(extra); + extra=0; + } + else{ + SDL_Rect dummy={0,0,0,0}; + extra=new DiviMenu(this); + extra->SetText("EXTRAS",dummy,DM_EXTRAS); + extra->SetText("SCREENSHOT",dummy,DM_SCREENSHOT); + extra->Generate(); + AddWidget(extra,VL_EXTRAS); + retval=true; + } + return retval; +} + +void DiviDead::ClearMenu(){ + if(main){ + DestroyWidget(main); + main=0; + } + if(extra){ + DestroyWidget(extra); + extra=0; + } + divigui->Clear(); +} + +const uString DiviDead::NativeID(){ + return "Divi"; +} + +const uString DiviDead::NativeName(){ + return "DiviDead"; +} + +bool DiviDead::EventLoad(int Index){ + DestroyLayer(VL_OVERLAY); + DestroyLayer(VL_EXTRAS); + ClearMenu(); + return EngineCWare::EventLoad(Index); +} + +bool DiviDead::EventBackgroundMouseRightUp(int X,int Y){ + DestroyLayer(VL_OVERLAY); + DestroyLayer(VL_EXTRAS); + ClearMenu(); + Resume(); + return true; +} + +void DiviDead::EventNew(){ + DestroyLayer(VL_OVERLAY); + DestroyLayer(VL_EXTRAS); + ClearMenu(); + LoadCWareScript("aastart"); +} + +void DiviDead::EventGameDialog(VN_DIALOGS Dialog){ + if(Dialog==VD_EXTRAS){ + // Stop game features + EngineCWare::EventGameDialog(Dialog); + AddWidget(new DiviCG(this),VL_EXTRAS); + } + else if(Dialog==VD_TITLE){ + // Clear up old rubble + StopMusic(); + StopSound(); + textview->ClearText(); + Stop(); + + // Show main screen graphics + SDL_Surface *title=LoadImage("title"); + SDL_Surface *frame=LoadImage("waku_a1"); + if(title && frame){ + display->Blit(frame); + display->Blit(title,0,&background); + SDL_FreeSurface(frame); + SDL_FreeSurface(title); + } + + // Load music + QueueMusic("opening.avi"); + } + else{ + EngineVN::EventGameDialog(Dialog); + } +} + + diff --git a/engines/vileVN/cware/dividead/dividead.h b/engines/vileVN/cware/dividead/dividead.h new file mode 100644 index 0000000000..18dfdcbc13 --- /dev/null +++ b/engines/vileVN/cware/dividead/dividead.h @@ -0,0 +1,36 @@ +/*! \class DiviDead + * \brief Dividead implementation + */ + +#ifndef _DIVIDEAD_H_ +#define _DIVIDEAD_H_ + +#include "../cware.h" +#include "divigui.h" +#include "divicg.h" + +class DiviDead : public EngineCWare { + private: + DiviGUI *divigui; + DiviMenu *main; + DiviMenu *extra; + public: + DiviDead(uString Path); + + // Menu interface + bool ToggleMainmenu(); + bool ToggleExtramenu(); + void ClearMenu(); + + // Overrides + virtual void EventNew(); + virtual bool EventLoad(int Index); + virtual void EventGameDialog(VN_DIALOGS Dialog); + virtual bool EventBackgroundMouseRightUp(int X,int Y); + virtual const uString NativeID(); + virtual const uString NativeName(); +}; + +#endif + + diff --git a/engines/vileVN/cware/dividead/divigui.cpp b/engines/vileVN/cware/dividead/divigui.cpp new file mode 100644 index 0000000000..920b9f3f76 --- /dev/null +++ b/engines/vileVN/cware/dividead/divigui.cpp @@ -0,0 +1,79 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "divigui.h" +#include "dividead.h" + +DiviGUI::DiviGUI(DiviDead *Engine) : DialogBase(Engine,false){ + // Add menu interface to background + mainmenu=0; + extramenu=0; + SDL_Surface *waku_p=Engine->LoadImage("waku_p"); + SDL_Surface *waku_a=Engine->LoadImage("waku_c1"); + if(waku_a && waku_p){ + Move(0,396); + Resize(640,64); + mainmenu=new ValueButton(); + SDL_Rect set={0,80,64,64}; + SDL_Rect unset={16,399,64,64}; + mainmenu->Resize(64,64); + mainmenu->Move(16,399); + mainmenu->SetState(WS_SELECT,waku_p,&set,waku_p,&set); + mainmenu->SetState(WS_NORMAL,waku_p,&set,waku_a,&unset); + mainmenu->SetState(WS_HOVER,waku_p,&set,waku_a,&unset); + + extramenu=new ValueButton(); + set.x+=64; + unset.x=640-(64+16); + extramenu->Resize(64,64); + extramenu->Move(640-(64+16),399); + extramenu->SetState(WS_SELECT,waku_p,&set,waku_p,&set); + extramenu->SetState(WS_NORMAL,waku_p,&set,waku_a,&unset); + extramenu->SetState(WS_HOVER,waku_p,&set,waku_a,&unset); + + + AddWidget(mainmenu); + AddWidget(extramenu); + SDL_FreeSurface(waku_p); + SDL_FreeSurface(waku_a); + } +} + +bool DiviGUI::InputOk(Widget *Object){ + bool retval=false; + if(Object){ + if(Object==mainmenu){ + if(extramenu->GetValue()){ + extramenu->SetValue(((DiviDead*)engine)->ToggleExtramenu()); + } + mainmenu->SetValue(((DiviDead*)engine)->ToggleMainmenu()); + retval=true; + } + if(Object==extramenu){ + if(mainmenu->GetValue()){ + mainmenu->SetValue(((DiviDead*)engine)->ToggleMainmenu()); + } + extramenu->SetValue(((DiviDead*)engine)->ToggleExtramenu()); + retval=true; + } + } + return retval; +} + +void DiviGUI::Clear(){ + mainmenu->SetValue(0); + extramenu->SetValue(0); +} + diff --git a/engines/vileVN/cware/dividead/divigui.h b/engines/vileVN/cware/dividead/divigui.h new file mode 100644 index 0000000000..e467433a7c --- /dev/null +++ b/engines/vileVN/cware/dividead/divigui.h @@ -0,0 +1,24 @@ +/*! \class DiviGUI + * \brief Provides buttons to open up the menu interface + */ +#ifndef _DIVIGUI_H_ +#define _DIVIGUI_H_ + +#include "../../dialogs/dlgbase.h" +#include "divimenu.h" + +class DiviGUI : public DialogBase { + private: + // Remember objects + ValueButton *mainmenu; + ValueButton *extramenu; + + // Override events + virtual bool InputOk(Widget *Object); + public: + DiviGUI(DiviDead *Engine); + void Clear(); +}; + +#endif + diff --git a/engines/vileVN/cware/dividead/divimenu.cpp b/engines/vileVN/cware/dividead/divimenu.cpp new file mode 100644 index 0000000000..cda8fadfdd --- /dev/null +++ b/engines/vileVN/cware/dividead/divimenu.cpp @@ -0,0 +1,119 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "divimenu.h" +#include "dividead.h" + +DiviMenu::DiviMenu(DiviDead *Engine) : Selection(Engine){ + SDL_Surface *tmps=Engine->LoadImage("waku_p"); + if(tmps){ + graphics=EDL_ColorkeySurface(tmps,0x00FF0000,0); + SDL_FreeSurface(tmps); + } +} + +DiviMenu::~DiviMenu(){ + if(graphics){ + SDL_FreeSurface(graphics); + } +} + +void DiviMenu::Generate(){ + // Generate and set background + int count=GetWidgetCount(); + int x=100; + int y=100; + int width=240; + int header=36; + int bottom=20; + int item=20; + int height=header+bottom+(item*count); + SDL_Rect rs={0,0,width,header}; + SDL_Surface *surface=EDL_CreateSurface(width,height); + EDL_BlitSurface(graphics,&rs,surface,0); + rs.y+=header; + rs.h=item; + for(int i=0;iMove(x+20,y+header+(item*i)+4); + w->Resize(width-40,item); + } + } +} + +bool DiviMenu::InputOk(Widget *Object){ + bool retval=false; + DiviDead *dengine=(DiviDead*)engine; + if(Object && dengine){ + int tag=Object->GetTag(); + if(tag==DM_NEW){ + dengine->ClearMenu(); + dengine->EventNew(); + retval=true; + } + if(tag==DM_LOAD){ + dengine->ClearMenu(); + dengine->EventGameDialog(VD_LOAD); + retval=true; + } + if(tag==DM_SAVE){ + dengine->ClearMenu(); + dengine->EventGameDialog(VD_SAVE); + retval=true; + } + if(tag==DM_CONFIG){ + dengine->ClearMenu(); + dengine->EventGameDialog(VD_OPTIONS); + retval=true; + } + if(tag==DM_EXIT){ + dengine->ClearMenu(); + dengine->EventGameDialog(VD_SHUTDOWN); + retval=true; + } + if(tag==DM_EXTRAS){ + dengine->ClearMenu(); + dengine->EventGameDialog(VD_EXTRAS); + retval=true; + } + if(tag==DM_SCREENSHOT){ + dengine->ClearMenu(); + dengine->AddWidget(new StdMessage(dengine, + "Title","Text"),VL_OVERLAY); + } + } + if(retval){ + engine->DestroyWidget(this); + } + return retval; +} + diff --git a/engines/vileVN/cware/dividead/divimenu.h b/engines/vileVN/cware/dividead/divimenu.h new file mode 100644 index 0000000000..a4ea0f24f4 --- /dev/null +++ b/engines/vileVN/cware/dividead/divimenu.h @@ -0,0 +1,29 @@ +#ifndef _DIVIMENU_H_ +#define _DIVIMENU_H_ + +#include "../../dialogs/selection.h" + +enum DIVIMENU { + DM_NEW=0x100, + DM_LOAD, + DM_SAVE, + DM_CONFIG, + DM_EXIT, + DM_EXTRAS, + DM_SCREENSHOT +}; + +class DiviDead; + +class DiviMenu : public Selection { + private: + SDL_Surface *graphics; + public: + DiviMenu(DiviDead *Engine); + ~DiviMenu(); + void Generate(); + virtual bool InputOk(Widget *Object); +}; + +#endif + diff --git a/engines/vileVN/detection.cpp b/engines/vileVN/detection.cpp new file mode 100644 index 0000000000..b65aea0036 --- /dev/null +++ b/engines/vileVN/detection.cpp @@ -0,0 +1,182 @@ +//#include "vileVN/vile.h" + +#include "base/plugins.h" + +#include "engines/advancedDetector.h" + +#define PROBESUF(name, platform) PROBESUFFULL(name, name,platform, Common::EN_ANY), \ + PROBESUFFULL(name, name,platform, Common::JA_JPN), \ + PROBESUFFULL(name, name,platform, Common::RU_RUS) + +#define PROBESUFFULL(name, name2, platform, lang) \ + {name, 0, AD_ENTRY1s("game.suf", NULL, -1), lang, platform, ADGF_NO_FLAGS, GUIO1(GUIO_NONE)}, \ + {name, 0, AD_ENTRY1s("us.suf", NULL, -1), lang, platform, ADGF_NO_FLAGS, GUIO1(GUIO_NONE)}, \ + {name, 0, AD_ENTRY1s("ml.suf", NULL, -1), lang, platform, ADGF_NO_FLAGS, GUIO1(GUIO_NONE)}, \ + {name, 0, AD_ENTRY1s(name2 ".suf", NULL, -1), lang, platform, ADGF_NO_FLAGS, GUIO1(GUIO_NONE)}, \ + {name, 0, AD_ENTRY1s(name2 "us.suf", NULL, -1), lang, platform, ADGF_NO_FLAGS, GUIO1(GUIO_NONE)}, \ + { name, 0, AD_ENTRY1s(name2 "ml.suf", NULL, -1), lang, platform, ADGF_NO_FLAGS, GUIO1(GUIO_NONE) } + +namespace VileVN { +//const char *VileVNEngine::getGameId() const { return _gameDescription->gameId; } +//Common::Platform VileVNEngine::getPlatform() const { return _gameDescription->platform; } + +} // namespace VileVN + +static const PlainGameDescriptor VileVNGames[] = { + {"mayclub", "May Club", "WIP", "https://vndb.org/v190"}, + {"mayclub2", "May Club 2", "WIP", "https://vndb.org/v190"}, + {"nocIll", "Nocturnal Illusion", "WIP", "https://vndb.org/v190"}, + {"cres", "Crescendo ~Eien da to Omotte Ita Ano Koro~", "WIP", "https://vndb.org/v29"}, + {"sagara", "Sagara-sanchi no Etsuraku Life", "WIP", "https://vndb.org/v46"}, + {"yuki", "Yuki Sakura", "WIP", "https://vndb.org/v71"}, + {"kanaoka", "Kana ~Imouto~", "WIP", "https://vndb.org/v2"}, + {"hitomi", "Gimai - Hitomi", "WIP", "https://vndb.org/v31"}, + {"koneko", "Koneko Doumei", "WIP", "https://vndb.org/v153"}, + {"mesia", "Meshimase Idol", "WIP", "https://vndb.org/v141"}, + {0, 0, 0, 0}}; + +namespace VileVN { + +static const ADGameDescription gameDescriptions[] = { + //May Club 1 + {"mayclub", + 0, + {{"may0.dat", 0, NULL, -1}, + {"may0.lst", 0, NULL, -1}, + {"cg/graphics.pak", 0, NULL, -1}, + {"wave/n02_88.wav", 0, NULL, -1}, + AD_LISTEND}, + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_NO_FLAGS, + GUIO1(GUIO_NONE)}, + {"mayclub", + 0, + {{"may0.dat", 0, NULL, -1}, + {"may0.lst", 0, NULL, -1}, + {"cg/graphics.pak", 0, NULL, -1}, + {"wave/n02_88.wav", 0, NULL, -1}, + AD_LISTEND}, + Common::EN_ANY, + Common::kPlatformPC98, + ADGF_NO_FLAGS, + GUIO1(GUIO_NONE)}, + {"mayclub", + 0, + {{"may0.dat", 0, NULL, -1}, + {"may0.lst", 0, NULL, -1}, + {"cg/graphics.pak", 0, NULL, -1}, + {"wave/n02_88.wav", 0, NULL, -1}, + AD_LISTEND}, + Common::EN_ANY, + Common::kPlatformMacintosh, + ADGF_NO_FLAGS, + GUIO1(GUIO_NONE)}, + {"mayclub", + 0, + {{"may0.dat", 0, NULL, -1}, + {"may0.lst", 0, NULL, -1}, + {"cg/graphics.pak", 0, NULL, -1}, + {"wave/n02_88.wav", 0, NULL, -1}, + AD_LISTEND}, + Common::EN_ANY, + Common::kPlatformLinux, + ADGF_NO_FLAGS, + GUIO1(GUIO_NONE)}, + + //May Club 2 + {"mayclub2", + 0, + {{"may0.dat", 0, NULL, -1}, + {"may0.lst", 0, NULL, -1}, + {"cg/graphics.pak", 0, NULL, -1}, + {"wave/n02_88.wav", 0, NULL, -1}, + AD_LISTEND}, + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_NO_FLAGS, + GUIO1(GUIO_NONE)}, + + //Nocturnal Illusion + {"nocIll", + 0, + {{"mug0.dat", 0, NULL, -1}, + {"mug0.lst", 0, NULL, -1}, + AD_LISTEND}, + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_NO_FLAGS, + GUIO1(GUIO_NONE)}, + + //Crescendo + PROBESUF("cres", Common::kPlatformWindows), + PROBESUF("cres", Common::kPlatformMacintosh), + PROBESUF("cres", Common::kPlatformLinux), + + //Sagara + PROBESUF("sagara", Common::kPlatformWindows), + + //Yuki Sakura + PROBESUF("yuki", Common::kPlatformWindows), + + //Kanao Okaeri + PROBESUF("kanaoka", Common::kPlatformWindows), + PROBESUF("kanaoka", Common::kPlatformMacintosh), + PROBESUF("kanaoka", Common::kPlatformLinux), + PROBESUF("kanaoka", Common::kPlatformPSP), + + PROBESUFFULL("kanaoka", "kana", Common::kPlatformWindows,Common::EN_ANY), + PROBESUFFULL("kanaoka", "kana", Common::kPlatformMacintosh,Common::EN_ANY), + PROBESUFFULL("kanaoka", "kana", Common::kPlatformLinux,Common::EN_ANY), + PROBESUFFULL("kanaoka", "kana", Common::kPlatformPSP,Common::EN_ANY), + + //Hitomi + PROBESUF("hitomi", Common::kPlatformWindows), + + //Cat Girl Alliance + PROBESUF("koneko", Common::kPlatformWindows), + + //Idols Galore + PROBESUF("mesia", Common::kPlatformWindows), + + AD_TABLE_END_MARKER}; + +} // End of namespace VileVN + +class VileVNMetaEngine : public AdvancedMetaEngine { +public: + VileVNMetaEngine() : AdvancedMetaEngine(VileVN::gameDescriptions, sizeof(ADGameDescription), VileVNGames) { + } + + const char *getEngineId() const override { + return "VileVN"; + } + + const char *getName() const override { + return "VileVN"; + } + + const char *getOriginalCopyright() const override { + return ""; + } + + bool hasFeature(MetaEngineFeature f) const override; + bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const override; +}; + +bool VileVNMetaEngine::hasFeature(MetaEngineFeature f) const { + return false; +} + +bool VileVNMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const { + if (desc) + ///*engine = new VileVN::VileVNEngine(syst, desc); + + return desc != nullptr; +} + +#if PLUGIN_ENABLED_DYNAMIC(VILEVN) +REGISTER_PLUGIN_DYNAMIC(VILEVN, PLUGIN_TYPE_ENGINE, VileVNMetaEngine); +#else +REGISTER_PLUGIN_STATIC(VILEVN, PLUGIN_TYPE_ENGINE, VileVNMetaEngine); +#endif diff --git a/engines/vileVN/dialogs/dlgbase.cpp b/engines/vileVN/dialogs/dlgbase.cpp new file mode 100644 index 0000000000..40104c6773 --- /dev/null +++ b/engines/vileVN/dialogs/dlgbase.cpp @@ -0,0 +1,630 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "dlgbase.h" +#include "../engine/evn.h" + +/*! \brief Creates a new dialog object + * \param Blockinput Wether to trap all user input + */ +DialogBase::DialogBase(EngineVN *Engine,bool Blockinput) : Widget() { + fhittable=true; + engine=Engine; + block=Blockinput; + layer=new Group(0); + defindex=0; + focus=0; +} + +DialogBase::~DialogBase(){ + // Destroy widgets + delete layer; +} + +Widget *DialogBase::GetFocus(){ + return focus; +} + +/*! \brief Sets focus to a specific widget + * \param WidgetPtr Widget to attain focus + * \return True if successfull + */ +bool DialogBase::SetFocus(Widget *WidgetPtr){ + Widget *wptr=WidgetPtr; + bool retval=engine->SetFocusWidget(this); + if(retval){ + retval=CheckWidget(wptr); + if(CheckWidget(wptr)){ + if(focus!=wptr){ + if(!FocusEnter(wptr)){ + wptr->FocusEnter(); + } + if(CheckWidget(focus)){ + if(!FocusLeave(focus)){ + focus->FocusLeave(); + } + } + focus=wptr; + } + } + } + return retval; +} + +/*! \brief Adds precreated widget + * \param WidgetPtr Pointer to precreated widget + * \returns Pointer to widget + */ +Widget *DialogBase::AddWidget(Widget *WidgetPtr){ + layer->AddWidget(WidgetPtr); + return WidgetPtr; +} + +/*! \brief Remove and destroy a given widget + * \param WidgetPtr Pointer to widget to destroy + */ +void DialogBase::DestroyWidget(Widget *WidgetPtr){ + layer->DestroyWidget(WidgetPtr); +} + +/*! \brief Remove and destroy all widgets in the dialog + */ +void DialogBase::DestroyWidgets(){ + layer->DestroyGroup(); +} + +Widget *DialogBase::Select(){ + Widget *retval=focus; + if(CheckWidget(focus)){ + focus->FocusLeave(); + focus=0; + } + return retval; +} + +void DialogBase::MoveDialog(int X,int Y){ + Move(X,Y); + Widget *wptr=layer->GetWidget(0); + while(wptr){ + wptr->Move(wptr->GetX()+X,wptr->GetY()+Y); + wptr=wptr->NextPtr; + } +} + +/*! \brief Retrieves widget at given index + * \param Index Index starting with 0 + * \param Y Y coordinate + * \returns Pointer to widget at given coordinates or NULL + */ +Widget *DialogBase::GetWidget(int Index){ + return layer->GetWidget(Index); +} + +/*! \brief Retrieves widget at given spot + * \param X X coordinate + * \param Y Y coordinate + * \returns Pointer to widget at given coordinates or NULL + */ +Widget *DialogBase::GetWidget(int X,int Y){ + return layer->GetWidget(X,Y); +} + +int DialogBase::GetWidgetCount(){ + return layer->GetWidgetCount(); +} + +/*! \brief Verifies that a given widget is in dialogs layer + * \param WidgetPtr Pointer to check + * \returns True if pointer was found in dialog layer + */ +bool DialogBase::CheckWidget(Widget *WidgetPtr){ + Widget *wptr=layer->GetWidget(0); + while(wptr){ + if(wptr==WidgetPtr){ + return true; + } + else{ + wptr=wptr->NextPtr; + } + } + return false; +} + +bool DialogBase::GetLocalRefresh(SDL_Rect *Cliprect){ + Widget *wptr=layer->GetWidget(0); + SDL_Rect r; + while(wptr){ + if(wptr->GetLocalRefresh(&r)){ + Refresh(&r); + } + wptr=wptr->NextPtr; + } + return Widget::GetLocalRefresh(); +} + +bool DialogBase::PeekLocalRefresh(SDL_Rect *Cliprect){ + Widget *wptr=layer->GetWidget(0); + SDL_Rect r; + while(wptr){ + if(wptr->GetLocalRefresh(&r)){ + Refresh(&r); + } + wptr=wptr->NextPtr; + } + return Widget::PeekLocalRefresh(); +} + +bool DialogBase::TestMouse(int X,int Y){ + if(block){ + // Trap all input + //return true; + return fvisible; + } + else{ + return Widget::TestMouse(X,Y); + } +} + +/*! \brief Tests wether dialog or any of the embedded widgets takes key focus + * \param Key Key code to test with + * \return True if keyboard input was accepted + */ +bool DialogBase::TestKey(SDLKey Key){ + bool retval=Widget::TestKey(Key); + if(CheckWidget(focus)){ + retval=focus->TestKey(Key); + } + return retval; +} + +bool DialogBase::FocusEnter(){ + bool retval=false; + if(CheckWidget(focus)){ + if(!(retval=FocusEnter(focus))){ + retval=focus->FocusEnter(); + } + } + return retval; +} + +bool DialogBase::FocusLeave(){ + bool retval=false; + if(CheckWidget(focus)){ + if(!(retval=FocusLeave(focus))){ + retval=focus->FocusLeave(); + } + } + return retval; +} + +bool DialogBase::FocusEnter(Widget *Object){ + return false; +} + +bool DialogBase::FocusLeave(Widget *Object){ + return false; +} + +/*! \brief Takes input and determines focus before passing event down to widget + * \param X X Coordinate relatative to games native resolution + * \param Y Y Coordinate relatative to games native resolution + * \return True if a widget accepted the input + */ +bool DialogBase::MouseMove(int X,int Y){ + // Set widget focus + bool retval=false; + Widget *wptr=GetWidget(X,Y); + if(wptr && wptr!=focus){ + if(wptr->GetVisible() && wptr->GetHittable()){ + if(!FocusEnter(wptr)){ + wptr->FocusEnter(); + } + if(CheckWidget(focus)){ + if(!FocusLeave(focus)){ + focus->FocusLeave(); + } + } + focus=wptr; + } + } + else if(!wptr && focus){ + if(CheckWidget(focus)){ + if(!FocusLeave(focus)){ + focus->FocusLeave(); + } + } + LogDebug("Mouse unsets dialog focus"); + focus=0; + } + + // Pass down mousemove event + if(!(retval=MouseMove(wptr,X,Y))){ + if(wptr){ + retval=wptr->MouseMove(X,Y); + } + } + return retval|block; +} + +/*! \brief Takes input and passes event down to widget + * \param X X Coordinate relatative to games native resolution + * \param Y Y Coordinate relatative to games native resolution + * \return True if a widget accepted the input + */ +bool DialogBase::MouseLeftDown(int X,int Y){ + bool retval=false; + Widget *wptr=GetWidget(X,Y); + if(wptr){ + // Pass down event + if(!(retval=MouseLeftDown(wptr,X,Y))){ + if(!(retval=InputOk(wptr))){ + retval=wptr->MouseLeftDown(X,Y); + } + } + } + return retval|block; +} + +/*! \brief Takes input and passes event down to widget + * \param X X Coordinate relatative to games native resolution + * \param Y Y Coordinate relatative to games native resolution + * \return True if a widget accepted the input + */ +bool DialogBase::MouseRightDown(int X,int Y){ + bool retval=false; + Widget *wptr=GetWidget(X,Y); + if(wptr){ + // Pass down event + if(!(retval=MouseRightDown(wptr,X,Y))){ + if(!(retval=InputCancel(wptr))){ + retval=wptr->MouseRightDown(X,Y); + } + } + } + return retval|block; +} + +/*! \brief Takes input and passes event down to widget + * \param X X Coordinate relatative to games native resolution + * \param Y Y Coordinate relatative to games native resolution + * \return True if a widget accepted the input + */ +bool DialogBase::MouseLeftUp(int X,int Y){ + bool retval=false; + Widget *wptr=GetWidget(X,Y); + if(wptr){ + // Pass down event + if(!(retval=MouseLeftUp(wptr,X,Y))){ + retval=wptr->MouseLeftUp(X,Y); + } + + // Unset focus if the event was accepted + if(retval){ + if(CheckWidget(wptr)){ + MouseMove(X,Y); + } + } + } + return retval|block; +} + +/*! \brief Takes input and passes event down to widget + * \param X X Coordinate relatative to games native resolution + * \param Y Y Coordinate relatative to games native resolution + * \return True if a widget accepted the input + */ +bool DialogBase::MouseRightUp(int X,int Y){ + bool retval=false; + Widget *wptr=GetWidget(X,Y); + if(wptr){ + // Pass down event + if(!(retval=MouseRightUp(wptr,X,Y))){ + retval=wptr->MouseRightUp(X,Y); + } + + // Unset focus if the event was accepted + if(retval){ + MouseMove(X,Y); + } + } + return retval|block; +} + +/*! \brief Distributes keyboard input to a focused widget + * \param Key Passed key + * \return True if widget accepted the event + * + * Passing false back to the engine drops engine focus, only do this when + * focus is being willfully released or when no child widgets can accept + * the input. + */ +bool DialogBase::KeyDown(SDLKey Key){ + bool retval=false; + if(CheckWidget(focus)){ + if(KEY_REFOCUS(Key)){ + // Ignore reserved key + retval=true; + } + else if(KeyDown(focus,Key)){ + // Event was handled by the dialog + LogDebug("Dialog handled keyboard event"); + retval=true; + } + else if(KEY_ACTION_OK(Key) && InputOk(focus)){ + // Event was handled by the dialog + LogDebug("Dialog handled ok event"); + retval=true; + } + else if(KEY_ACTION_CANCEL(Key) && InputCancel(focus)){ + // Event was handled by the dialog + LogDebug("Dialog handled cancel event"); + retval=true; + } + else if(focus->KeyDown(Key)){ + // Event was handled by the widget + LogDebug("Keyboard event passed to widget"); + retval=true; + } + else if(KEY_DIRECTION(Key)){ + // Change focus + InputDirection(Key); + retval=true; + } + else if(KEY_ACTION_CANCEL(Key)){ + // Escape focus + LogDebug("Dialog cancelled keyboard focus"); + if(!FocusLeave(focus)){ + focus->FocusLeave(); + } + focus=0; + } + else{ + // Ignore keys per default + retval=true; + } + } + else if(KEY_DIRECTION(Key) || KEY_REFOCUS(Key)){ + // Search for first available focus + focus=0; + for(int i=layer->GetWidgetCount()-1;!focus && i>=0;i--){ + focus=GetWidget(i); + if(focus){ + if(focus->GetVisible() && focus->GetHittable()){ + if(!FocusEnter(focus)){ + focus->FocusEnter(); + } + retval=true; + break; + } + else{ + focus=0; + } + } + } + if(retval){ + LogDebug("Dialog reset focus"); + } + else{ + LogDebug("Dialog refrained focus"); + } + } + else{ + // No valid focus or related keys + LogDebug("Dialog refrained keyboard event"); + } + return retval|block; +} + +bool DialogBase::KeyUp(SDLKey Key){ + //LogMessage("DIALOG:KEYUP:%d",Key); + bool retval=true; + if(CheckWidget(focus)){ + if(KEY_REFOCUS(Key)){ + // Ignore reserved key + } + else if(!(retval=KeyUp(focus,Key))){ + // Pass all keyup events to widgets + retval=focus->KeyUp(Key); + } + } + return retval; +} + +bool DialogBase::InputDirection(SDLKey Key){ + bool retval=false; + if(KEY_DIRECTION(Key) && CheckWidget(focus)){ + // Find current items center position + Widget *test=0; + Widget *candidate=0; + int fx1,fy1,fx2,fy2; + + // Vertical navigation + if(KEY_DIRECTION_V(Key)){ + fy1=focus->GetY(); + fy2=fy1+focus->GetHeight(); + fx1=fx2=focus->GetX()+(focus->GetWidth()/2); + for(int i=0;!candidate && iGetX(); + int ty1=test->GetY(); + int tx2=tx1+test->GetWidth(); + int ty2=ty1+test->GetHeight(); + bool l1=Key==SDLK_UP?(fy1>ty1):(fy2tx1 && tx2>lfx2); + if(test!=focus && l1 && (l2 || l3 || l4)){ + if(test->GetVisible() && test->GetHittable()){ + // We got an eligable candidate + if(candidate){ + // Compare object to current candidate + int cy1=candidate->GetY(); + int cy2=cy1+candidate->GetHeight(); + if(Key==SDLK_UP?(ty2>cy2):(ty1GetX(); + fx2=fx1+focus->GetWidth(); + fy1=fy2=focus->GetY()+(focus->GetHeight()/2); + for(int i=0;!candidate && iGetX(); + int ty1=test->GetY(); + int tx2=tx1+test->GetWidth(); + int ty2=ty1+test->GetHeight(); + bool l1=Key==SDLK_LEFT?(fx1>tx1):(fx2ty1 && ty2>lfy2); + if(test!=focus && l1 && (l2 || l3 || l4)){ + if(test->GetVisible() && test->GetHittable()){ + // We got an eligable candidate + if(candidate){ + // Compare object to current candidate + int cx1=candidate->GetX(); + int cx2=cx1+candidate->GetWidth(); + if(Key==SDLK_LEFT?(tx2>cx2):(tx1FocusLeave(); + } + if(!FocusEnter(candidate)){ + candidate->FocusEnter(); + } + focus=candidate; + retval=true; + } + } + return retval; +} + +/*! \brief Dialog event that is called when an OK button has been pressed + * \param Object Object that recieved the event + * \return True if the event was accepted + */ +bool DialogBase::InputOk(Widget *Object){ + return false; +} + +/*! \brief Dialog event that is called when an CANCEL button has been pressed + * \param Object Object that recieved the event + * \return True if the event was accepted + */ +bool DialogBase::InputCancel(Widget *Object){ + return false; +} + +/*! \brief Input event for widgets embedded in a dialog (Dialog event) + * \param Object Pointer to widget (NULL for loss of focus) + * \param X X coordinate + * \param Y Y coordinate + * \return True if dialog accepted the event + */ +bool DialogBase::MouseMove(Widget *Object,int X,int Y){ + return false; +} + +bool DialogBase::MouseLeftUp(Widget *Object,int X,int Y){ + return false; +} + +bool DialogBase::MouseRightUp(Widget *Object,int X,int Y){ + return false; +} + +bool DialogBase::MouseLeftDown(Widget *Object,int X,int Y){ + return false; +} + +bool DialogBase::MouseRightDown(Widget *Object,int X,int Y){ + return false; +} + +bool DialogBase::KeyUp(Widget *Object,SDLKey Key){ + return false; +} + +bool DialogBase::KeyDown(Widget *Object,SDLKey Key){ + return false; +} + +void DialogBase::Tick(){ + Widget *wptr=layer->GetWidget(0); + Widget *pptr=0; + while(CheckWidget(wptr)){ + // Distribute event + wptr->Tick(); + + // Check for dropped items and iterate + if(CheckWidget(wptr)){ + pptr=wptr; + wptr=wptr->NextPtr; + } + else if(CheckWidget(pptr)){ + wptr=pptr->NextPtr; + pptr=0; + } + else{ + LogError("Invalid stackpointer in dialog"); + break; + } + } +} + +void DialogBase::Copy(SDL_Surface *Dst){ + if(fvisible){ + // Copy own graphics as background + Widget::Copy(Dst); + + // Copy children widgets graphics over our own + Widget *wptr=layer->GetWidget(layer->GetWidgetCount()-1); + while(wptr){ + if(wptr->GetVisible()){ + wptr->Copy(Dst); + } + wptr=wptr->PrevPtr; + } + } +} + diff --git a/engines/vileVN/dialogs/dlgbase.h b/engines/vileVN/dialogs/dlgbase.h new file mode 100644 index 0000000000..f066cd9f03 --- /dev/null +++ b/engines/vileVN/dialogs/dlgbase.h @@ -0,0 +1,106 @@ +/*! \class DialogBase + * \brief Organizes and handles widgets in a dialog sense + * + * The Dialog class distributes events between the derived dialog and the + * widgets within it. A MouseLeftDown event from the engine will be handled + * if(!(retval=MouseLeftDown(wptr,X,Y))){ + * if((retval=wptr->MouseLeftDown(X,Y))){ + * retval=InputOk(wptr); + * } + * } + * + * The first and last calls are sent to the derived dialog which might + * intercept and optionally block further processing of the event by + * returning true. + * + * Normally you will want to override the InputOk() method. + */ +#ifndef _DLGBASE_H_ +#define _DLGBASE_H_ + +#include "../widgets/group.h" +#include "../widgets/hotspot.h" +#include "../widgets/sprite.h" +#include "../widgets/printer.h" +#include "../widgets/tbutton.h" +#include "../widgets/bbutton.h" +#include "../widgets/vbutton.h" +#include "../widgets/checkbox.h" +#include "../widgets/slider.h" +#include "../widgets/saveslab.h" +#include "../widgets/fade.h" +#include "../widgets/zoom.h" +#include "../widgets/slide.h" +#include "../widgets/scroll.h" + +// Forward declaration of the engine classes +class EngineVN; + +class DialogBase : public Widget { + private: + bool block; + Widget *focus; + Group *layer; + int defindex; + protected: + // Protected constructors + DialogBase(EngineVN *Engine,bool Blockinput); + ~DialogBase(); + + // Configure widgets + Widget *AddWidget(Widget *WidgetPtr); + void DestroyWidget(Widget *WidgetPtr); + void DestroyWidgets(); + + // Access to parent engine + EngineVN *engine; + public: + // Widget overrides + virtual void Copy(SDL_Surface *Dst); + virtual bool TestKey(SDLKey Key); + virtual bool TestMouse(int X,int Y); + virtual bool GetLocalRefresh(SDL_Rect *Cliprect); + virtual bool PeekLocalRefresh(SDL_Rect *Cliprect); + + bool SetFocus(Widget *WidgetPtr); + Widget *GetFocus(); + + // Handle events + virtual void Tick(); + virtual bool FocusEnter(); + virtual bool FocusLeave(); + virtual bool MouseMove(int X,int Y); + virtual bool MouseLeftUp(int X,int Y); + virtual bool MouseRightUp(int X,int Y); + virtual bool MouseLeftDown(int X,int Y); + virtual bool MouseRightDown(int X,int Y); + virtual bool KeyUp(SDLKey Key); + virtual bool KeyDown(SDLKey Key); + + // Declare dialog events + virtual bool MouseMove(Widget *Object,int X,int Y); + virtual bool MouseLeftUp(Widget *Object,int X,int Y); + virtual bool MouseRightUp(Widget *Object,int X,int Y); + virtual bool MouseLeftDown(Widget *Object,int X,int Y); + virtual bool MouseRightDown(Widget *Object,int X,int Y); + virtual bool KeyUp(Widget *Object,SDLKey Key); + virtual bool KeyDown(Widget *Object,SDLKey Key); + virtual bool FocusEnter(Widget *Object); + virtual bool FocusLeave(Widget *Object); + virtual bool InputOk(Widget *Object); + virtual bool InputCancel(Widget *Object); + virtual bool InputDirection(SDLKey Key); + + // Manage focus + virtual Widget *Select(); + + // Retrieve widgets in various ways + void MoveDialog(int X,int Y); + bool CheckWidget(Widget *WidgetPtr); + int GetWidgetCount(); + Widget *GetWidget(int X,int Y); + Widget *GetWidget(int Index); +}; + +#endif + diff --git a/engines/vileVN/dialogs/fatal.cpp b/engines/vileVN/dialogs/fatal.cpp new file mode 100644 index 0000000000..6ff263553d --- /dev/null +++ b/engines/vileVN/dialogs/fatal.cpp @@ -0,0 +1,37 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "fatal.h" +#include "../engine/evn.h" + +Fatal::Fatal(EngineVN *Engine,uString Title,uString Message) + : StdMessage(Engine,Title,Message){ +} + +Fatal::~Fatal(){ + DestroyWidgets(); +} + +bool Fatal::InputOk(Widget *Object){ + bool retval=false; + if(Object==w_ok){ + // Close dialog + engine->DestroyWidget(this); + engine->EventGameShutdown(); + retval=true; + } + return retval; +} + diff --git a/engines/vileVN/dialogs/fatal.h b/engines/vileVN/dialogs/fatal.h new file mode 100644 index 0000000000..875515d551 --- /dev/null +++ b/engines/vileVN/dialogs/fatal.h @@ -0,0 +1,19 @@ +/*! \class Fatal + * \brief Presents a message before shutting down the application + */ +#ifndef _FATAL_H_ +#define _FATAL_H_ + +#include "stdmsg.h" + +class Fatal : public StdMessage { + private: + // Override events + virtual bool InputOk(Widget *Object); + public: + Fatal(EngineVN *Engine,uString Title,uString Message); + ~Fatal(); +}; + +#endif + diff --git a/engines/vileVN/dialogs/options.cpp b/engines/vileVN/dialogs/options.cpp new file mode 100644 index 0000000000..48b0ca5f34 --- /dev/null +++ b/engines/vileVN/dialogs/options.cpp @@ -0,0 +1,251 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "options.h" +#include "../engine/evn.h" + +Options::Options(EngineVN *Engine) : DialogBase(Engine,true){ + // Create background graphics + SDL_Rect rfull={0,0,Engine->NativeWidth(),Engine->NativeHeight()}; + Move(rfull); + Fill(Cfg::Color::DialogBackground); + int space=rfull.h/20; + SDL_Rect rtmp={space,space,rfull.w,rfull.h/10}; + EDL_BlendText("Configuration",Cfg::Color::DialogHeader,simage,&rtmp); + rtmp.y=rfull.h/4; + rtmp.h=rtmp.h/2; + EDL_BlendText("Graphics",Cfg::Color::DialogTopic,simage,&rtmp); + rtmp.x=space+rfull.w/2; + EDL_BlendText("Audio",Cfg::Color::DialogTopic,simage,&rtmp); + rtmp.x=space; + rtmp.y=rfull.h/2; + EDL_BlendText("Generic",Cfg::Color::DialogTopic,simage,&rtmp); + + + // Fullscreen setting + rtmp.x=space*2; + rtmp.y=(rfull.h/4)+space*1; + rtmp.w=rfull.w/2; + rtmp.h=space; + cb_fullscreen=new Checkbox(rtmp,"Fullscreen mode"); + cb_fullscreen->SetValue(Engine->GetFullscreen()); + + // BGM control + rtmp.x=(rfull.w/2)+space*2; + rtmp.y=(rfull.h/4)+space*1; + rtmp.w=rfull.w/5; + rtmp.h=space; + cb_bgm=new Checkbox(rtmp,"Music"); + cb_bgm->SetValue(Engine->GetMusicEnabled()); + cb_bgm->SetOrientation(false); + rtmp.x+=rtmp.w+4; + rtmp.w=rfull.w/6; + sl_bgm=new Slider(rtmp); + sl_bgm->SetValue(Engine->GetVolumeMusic()); + + // SE control + rtmp.x=(rfull.w/2)+space*2; + rtmp.y=(rfull.h/4)+space*2; + rtmp.w=rfull.w/5; + rtmp.h=space; + cb_se=new Checkbox(rtmp,"SE"); + cb_se->SetOrientation(false); + cb_se->SetValue(Engine->GetSoundEnabled(VA_SOUNDS)); + rtmp.x+=rtmp.w+4; + rtmp.w=rfull.w/6; + sl_se=new Slider(rtmp); + sl_se->SetValue(Engine->GetVolumeSound(VA_SOUNDS)); + + // Voice control + rtmp.x=(rfull.w/2)+space*2; + rtmp.y=(rfull.h/4)+space*3; + rtmp.w=rfull.w/5; + rtmp.h=space; + cb_voice=new Checkbox(rtmp,"Voices"); + cb_voice->SetOrientation(false); + cb_voice->SetValue(Engine->GetSoundEnabled(VA_VOICES)); + rtmp.x+=rtmp.w+4; + rtmp.w=rfull.w/6; + sl_voice=new Slider(rtmp); + sl_voice->SetValue(engine->GetVolumeSound(VA_VOICES)); + + // Create buttons + int buttonw=rfull.w/6; + int buttonh=Cfg::Font::default_size*1.5; + int emptyw=(rfull.w-(buttonw*5))/6; + EDL_SETRECT(rtmp,emptyw,rfull.h-(buttonh+emptyw),buttonw,buttonh); + tb_load=new BitmapButton(rtmp); + tb_load->SetCaption("Load"); + rtmp.x+=rtmp.w+emptyw; + tb_save=new BitmapButton(rtmp); + tb_save->SetCaption("Save"); + rtmp.x+=rtmp.w+emptyw; + tb_title=new BitmapButton(rtmp); + tb_title->SetCaption("Title"); + rtmp.x+=rtmp.w+emptyw; + tb_exit=new BitmapButton(rtmp); + tb_exit->SetCaption("Exit"); + rtmp.x+=rtmp.w+emptyw; + tb_resume=new BitmapButton(rtmp); + tb_resume->SetCaption("Resume"); + + // Delay control + rtmp.x=space*2; + rtmp.y=(rfull.h/2)+space; + rtmp.w=rfull.w/5; + rtmp.h=space; + cb_delay=new Checkbox(rtmp,"Text delay"); + cb_delay->SetValue(Engine->GetMessageDelayEnabled()); + cb_delay->SetOrientation(false); + rtmp.x+=rtmp.w+4; + rtmp.w=rfull.w/6; + sl_delay=new Slider(rtmp); + sl_delay->SetValue(Engine->GetMessageDelayInterval()); + + // Add widgets to the dialog + AddWidget(cb_fullscreen); + AddWidget(cb_delay); + AddWidget(sl_delay); + AddWidget(cb_bgm); + AddWidget(sl_bgm); + AddWidget(cb_se); + AddWidget(sl_se); + AddWidget(cb_voice); + AddWidget(sl_voice); + AddWidget(tb_load); + AddWidget(tb_save); + AddWidget(tb_title); + AddWidget(tb_exit); + AddWidget(tb_resume); +} + +Options::~Options(){ +} + +/*! \brief Passes mouse event to widget and reads back updated values + * \param Object Widget object that recieved the event + * \param X Mouse coordinate + * \param Y Mouse coordinate + * + * Passes mouse event to widget (Usually a slider) and reads back the + * updated value and passes it to the relevant engine member (Ie. set + * bgm volume etc). + */ +bool Options::MouseMove(Widget* Object,int X,int Y){ + bool retval=false; + if(Object==sl_delay){ + sl_delay->MouseMove(X,Y); + engine->SetMessageDelayInterval(sl_delay->GetValue()); + retval=true; + } + else if(Object==sl_bgm){ + sl_bgm->MouseMove(X,Y); + engine->SetVolumeMusic(sl_bgm->GetValue()); + retval=true; + } + else if(Object==sl_se){ + sl_se->MouseMove(X,Y); + engine->SetVolumeSound(VA_SOUNDS,sl_se->GetValue()); + retval=true; + } + else if(Object==sl_voice){ + sl_voice->MouseMove(X,Y); + engine->SetVolumeSound(VA_VOICES,sl_voice->GetValue()); + retval=true; + } + return retval; +} + +bool Options::InputOk(Widget *Object){ + bool retval=false; + if(Object==cb_delay){ + engine->SetMessageDelayEnabled(!cb_delay->GetValue()); + } + else if(Object==cb_bgm){ + engine->SetMusicEnabled(!cb_bgm->GetValue()); + } + else if(Object==cb_se){ + engine->SetSoundEnabled(VA_SOUNDS,!cb_se->GetValue()); + } + else if(Object==cb_voice){ + engine->SetSoundEnabled(VA_VOICES,!cb_voice->GetValue()); + } + else if(Object==cb_fullscreen){ + engine->SetFullscreen(!cb_fullscreen->GetValue()); + } + else if(Object==tb_load){ + engine->DestroyWidget(this); + engine->EventGameDialog(VD_LOAD); + retval=true; + } + else if(Object==tb_save){ + engine->DestroyWidget(this); + engine->EventGameDialog(VD_SAVE); + retval=true; + } + else if(Object==tb_title){ + engine->DestroyWidget(this); + engine->EventGameDialog(VD_TITLE); + retval=true; + } + else if(Object==tb_resume){ + engine->DestroyWidget(this); + retval=true; + } + else if(Object==tb_exit){ + engine->EventGameDialog(VD_SHUTDOWN); + retval=true; + } + return retval; +} + +/*! \brief Passes mouse event to widget and reads back updated values + * \param Object Widget object that recieved the event + * \param X Mouse coordinate + * \param Y Mouse coordinate + * + * Passes mouse event to widget (Usually a slider) and reads back the + * updated value and passes it to the relevant engine member (Ie. set + * bgm volume etc). + */ +bool Options::MouseLeftDown(Widget* Object,int X,int Y){ + bool retval=false; + if(InputOk(Object)){ + // Input was accepted + retval=true; + } + else if(Object==sl_delay){ + sl_delay->MouseLeftDown(X,Y); + engine->SetMessageDelayInterval(sl_delay->GetValue()); + retval=true; + } + else if(Object==sl_bgm){ + sl_bgm->MouseLeftDown(X,Y); + engine->SetVolumeMusic(sl_bgm->GetValue()); + retval=true; + } + else if(Object==sl_se){ + sl_se->MouseLeftDown(X,Y); + engine->SetVolumeSound(VA_SOUNDS,sl_se->GetValue()); + retval=true; + } + else if(Object==sl_voice){ + sl_voice->MouseLeftDown(X,Y); + engine->SetVolumeSound(VA_VOICES,sl_voice->GetValue()); + retval=true; + } + return retval; +} + diff --git a/engines/vileVN/dialogs/options.h b/engines/vileVN/dialogs/options.h new file mode 100644 index 0000000000..21f58dc980 --- /dev/null +++ b/engines/vileVN/dialogs/options.h @@ -0,0 +1,38 @@ +/*! \class Options + * \brief Standard dialog for setting options + */ +#ifndef _OPTIONS_H_ +#define _OPTIONS_H_ + +#include "dlgbase.h" + +class Options : public DialogBase { + protected: + Checkbox *cb_fullscreen; + //Checkbox *cb_readonly; + Checkbox *cb_bgm; + Checkbox *cb_se; + Checkbox *cb_voice; + Checkbox *cb_delay; + Slider *sl_bgm; + Slider *sl_se; + Slider *sl_voice; + Slider *sl_delay; + BitmapButton *tb_load; + BitmapButton *tb_save; + BitmapButton *tb_title; + BitmapButton *tb_exit; + BitmapButton *tb_resume; + public: + Options(EngineVN *Engine); + ~Options(); + + // Hook into user input + bool MouseMove(Widget *Object,int X,int Y); + bool MouseLeftDown(Widget* Object,int X,int Y); + bool InputOk(Widget *Object); + +}; + +#endif + diff --git a/engines/vileVN/dialogs/popimage.cpp b/engines/vileVN/dialogs/popimage.cpp new file mode 100644 index 0000000000..74a99db587 --- /dev/null +++ b/engines/vileVN/dialogs/popimage.cpp @@ -0,0 +1,136 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "popimage.h" +#include "../engine/evn.h" + +PopImage::PopImage(EngineVN *Engine) : + DialogBase(Engine,true){ + // Configure container dialog + int w=Engine->NativeWidth(); + int h=Engine->NativeHeight(); + Move(0,0); + Resize(w,h); + + // Configure hotspot and display + widget=new Hotspot(); + widget->Move(0,0); + widget->Resize(w,h); + AddWidget(widget); + slides=0; +} + +PopImage::PopImage(EngineVN *Engine,SDL_Surface *Surface) : + DialogBase(Engine,true){ + // Configure container dialog + int w=Engine->NativeWidth(); + int h=Engine->NativeHeight(); + Move(0,0); + Resize(w,h); + Fill(0,0,0,0); + + // Configure hotspot and display + widget=new Hotspot(); + if(Surface){ + int x=(w-Surface->w)/2; + int y=(h-Surface->h)/2; + widget->Move(x,y); + widget->Resize(Surface->w,Surface->h); + widget->Blit(Surface); + } + AddWidget(widget); + slides=0; +} + +PopImage::~PopImage(){ + while(slides){ + SLIDES_TYPE *tmpptr=slides->next; + SDL_FreeSurface(slides->surface); + delete slides; + slides=tmpptr; + } +} + +/*! \brief Adds a manually positioned image + * \param Surface Image to display + * \param X Screen coordinate + * \param Y Screen coordinate + */ +void PopImage::AddImage(SDL_Surface *Surface,int X,int Y){ + if(widget->GetSurface()){ + // Queue image for later + if(slides){ + SLIDES_TYPE *tmpptr=slides; + while(tmpptr->next){ + tmpptr=tmpptr->next; + } + tmpptr->next=new SLIDES_TYPE; + tmpptr=tmpptr->next; + tmpptr->surface=EDL_CopySurface(Surface,0); + tmpptr->rect.x=X; + tmpptr->rect.y=Y; + tmpptr->rect.w=Surface->w; + tmpptr->rect.h=Surface->h; + tmpptr->next=0; + } + else{ + slides=new SLIDES_TYPE; + slides->surface=EDL_CopySurface(Surface,0); + slides->rect.x=X; + slides->rect.y=Y; + slides->rect.w=Surface->w; + slides->rect.h=Surface->h; + slides->next=0; + } + } + else{ + // Display image immidiatly + widget->Move(X,Y); + widget->Resize(Surface->w,Surface->h); + widget->Blit(Surface); + } + +} + +/*! \brief Adds a centered image + * \param Surface Image to display + */ +void PopImage::AddImage(SDL_Surface *Surface){ + int x=(GetWidth()-Surface->w)/2; + int y=(GetHeight()-Surface->h)/2; + AddImage(Surface,x,y); +} + +bool PopImage::InputOk(Widget *Object){ + if(slides){ + // Display image + widget->Move(slides->rect.x,slides->rect.y); + widget->Resize(slides->surface->w,slides->surface->h); + widget->Blit(slides->surface); + + // Drop from queue + SLIDES_TYPE *tmpptr=slides->next; + SDL_FreeSurface(slides->surface); + delete slides; + slides=tmpptr; + } + else{ + // Nothing more to display ... + engine->DestroyWidget(this); + } + return true; +} + + diff --git a/engines/vileVN/dialogs/popimage.h b/engines/vileVN/dialogs/popimage.h new file mode 100644 index 0000000000..08bae01aa6 --- /dev/null +++ b/engines/vileVN/dialogs/popimage.h @@ -0,0 +1,26 @@ +/* \class PopImage + * \brief Popup image that destroys itself upon user input + */ +#ifndef _POPIMAGE_H_ +#define _POPIMAGE_H_ + +#include "dlgbase.h" + +class PopImage : public DialogBase{ + private: + struct SLIDES_TYPE { + SDL_Surface *surface; + SDL_Rect rect; + SLIDES_TYPE *next; + }*slides; + Hotspot *widget; + public: + PopImage(EngineVN *Engine,SDL_Surface *Surface); + PopImage(EngineVN *Engine); + ~PopImage(); + void AddImage(SDL_Surface *Surface); + void AddImage(SDL_Surface *Surface,int X,int Y); + bool InputOk(Widget *Object); +}; + +#endif diff --git a/engines/vileVN/dialogs/selection.cpp b/engines/vileVN/dialogs/selection.cpp new file mode 100644 index 0000000000..46034f8a66 --- /dev/null +++ b/engines/vileVN/dialogs/selection.cpp @@ -0,0 +1,198 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "selection.h" +#include "../engine/evn.h" + +Selection::Selection(EngineVN *Engine) : DialogBase(Engine,false){ + bgscolor=0x000000FF; + fgscolor=0xFFFFFFFF; + bgucolor=0x000000FF; + fgucolor=0xA0A0A0FF; + halign=HA_LEFT; + valign=VA_TOP; + fontsize=18; +} + +Selection::~Selection(){ +} + +void Selection::Clear(){ + DestroyWidgets(); +} + +void Selection::SetFontSize(int Fontsize){ + fontsize=Fontsize; +} + +void Selection::SetAlignment(HALIGN Horizontal,VALIGN Vertical){ + halign=Horizontal; + valign=Vertical; +} + +void Selection::SetColors(Uint32 BGSColor,Uint32 FGSColor, + Uint32 BGUColor,Uint32 FGUColor){ + bgscolor=BGSColor; + fgscolor=FGSColor; + bgucolor=BGUColor; + fgucolor=FGUColor; +} + + +/*! \brief Registers two graphical surfaces as a item + * \param Selected Surface to use when selection is hovered + * \param Unselected Surface to use when selection is not hovered + * \param Rect Screen coordinates + * \param ID ID to be called back to EventSelect + */ +void Selection::SetSurface(SDL_Surface *Selected, + SDL_Surface *Unselected,SDL_Rect Rect,int ID){ + // Assert index + if(ID==-1){ + ID=GetWidgetCount(); + } + + // Create widget + BitmapButton *button=new BitmapButton(); + button->Resize(Rect.w,Rect.h); + button->Move(Rect.x,Rect.y); + button->SetTag(ID); + if(Selected){ + button->SetState(WS_HOVER,Selected,0); + } + if(Unselected){ + button->SetState(WS_NORMAL,Unselected,0); + } + AddWidget(button); +} + +/*! \brief Adds a textual menu item + * \param Caption Text string to display + * \param Rect Onscreen position + * \param ID Identification code + * + * The ID will be passed as an argument to the EventSelect() event. + */ +void Selection::SetText(uString Caption,SDL_Rect Area,int ID){ + if(Caption.length()){ + // Assert index + if(ID==-1){ + ID=GetWidgetCount(); + } + + // Create widget + TextButton *button=new TextButton(Area,Caption); + button->SetColorBackground(WS_HOVER,bgscolor); + button->SetColorForeground(WS_HOVER,fgscolor); + button->SetColorBackground(WS_NORMAL,bgucolor); + button->SetColorForeground(WS_NORMAL,fgucolor); + button->SetFontSize(fontsize); + button->SetAlignment(halign,valign); + button->SetTag(ID); + AddWidget(button); + } +} + +/*! \brief Populates a menu from a list of strings + * \param Captions Text strings to display + * \param BGSColor RGBA value of hovered background + * \param FGSColor RGBA value for hovered text + * \param BGUColor RGBA value of normal background + * \param FGUColor RGBA value for normal text + */ +void Selection::SetText(Stringlist *Captions){ + // Gather statistics + int count=0; + uString tmpstr; + for(int i=0;true;i++){ + if(Captions->GetString(i,&tmpstr)){ + count++; + } + else{ + break; + } + } + + // Build dialog widgets + if(count){ + int itemheight=pos.h/(count+1); + for(int i=0;true;i++){ + if(Captions->GetString(i,&tmpstr)){ + int x=pos.x; + int y=pos.y+(itemheight/2)+(i*itemheight); + int w=pos.w; + int h=itemheight; + TextButton *button=new TextButton(x,y,w,h,tmpstr); + button->SetColorBackground(WS_HOVER,bgscolor); + button->SetColorForeground(WS_HOVER,fgscolor); + button->SetColorBackground(WS_NORMAL,bgucolor); + button->SetColorForeground(WS_NORMAL,fgucolor); + button->SetFontSize(fontsize); + button->SetAlignment(halign,valign); + button->SetTag(GetWidgetCount()); + AddWidget(button); + } + else{ + break; + } + } + } +} + +int Selection::GetFocusItem(){ + int retval=-1; + Widget *widget=GetFocus(); + if(widget){ + retval=widget->GetTag(); + } + return retval; +} + +/*! \brief Focuses the indexed menu item + */ +void Selection::SetFocusItem(int ID){ + int count=GetWidgetCount(); + if(count){ + Widget *item=GetWidget(count-1); + while(item && item->GetTag()!=ID){ + item=item->PrevPtr; + } + if(!item){ + item=GetWidget(count-1); + } + SDL_Rect ipos={item->GetX(),item->GetY(), + item->GetWidth(),item->GetHeight()}; + if(ipos.w && ipos.h){ + // Get coordinates and warp cursor + int x=ipos.x+(ipos.w/2); + int y=ipos.y+(ipos.h/2); + engine->CursorWarp(x,y); + + // Focus item + SetFocus(item); + } + } +} + +bool Selection::InputOk(Widget *Object){ + bool retval=false; + if(Object){ + engine->EventSelect(Object->GetTag()); + retval=true; + } + return retval; +} + + diff --git a/engines/vileVN/dialogs/selection.h b/engines/vileVN/dialogs/selection.h new file mode 100644 index 0000000000..c196cb676f --- /dev/null +++ b/engines/vileVN/dialogs/selection.h @@ -0,0 +1,43 @@ +/*! \class Selection + * \brief Widget for displaying a load- or savegame + */ +#ifndef _SELECTION_H_ +#define _SELECTION_H_ + +#include "dlgbase.h" + +class Selection : public DialogBase { + private: + Uint32 bgscolor; + Uint32 fgscolor; + Uint32 bgucolor; + Uint32 fgucolor; + HALIGN halign; + VALIGN valign; + int fontsize; + public: + Selection(EngineVN *Engine); + ~Selection(); + + // API + void Clear(); + void SetFocusItem(int ID); + int GetFocusItem(); + void SetText(uString Caption,SDL_Rect Area,int ID=-1); + void SetText(Stringlist *Captions); + void SetSurface(SDL_Surface *Selected, + SDL_Surface *Unselected, + SDL_Rect Area,int ID=-1); + + // Configuration options for textbased menues + void SetFontSize(int Fontsize); + void SetAlignment(HALIGN Horizontal,VALIGN Vertical); + void SetColors(Uint32 BGSColor,Uint32 FGSColor, + Uint32 BGUColor,Uint32 FGUColor); + + // Hook into user input + bool InputOk(Widget* Object); +}; + +#endif + diff --git a/engines/vileVN/dialogs/stdhalt.cpp b/engines/vileVN/dialogs/stdhalt.cpp new file mode 100644 index 0000000000..7dfa5a2463 --- /dev/null +++ b/engines/vileVN/dialogs/stdhalt.cpp @@ -0,0 +1,85 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "stdhalt.h" +#include "../engine/evn.h" + +bool StdHalt::showing=false; + +StdHalt::StdHalt(EngineVN *Engine) : DialogBase(Engine,true){ + // Create background graphics + SDL_Rect rfull={0,0,Engine->NativeWidth(),Engine->NativeHeight()}; + Move(rfull); + Fill(Cfg::Color::DialogBackground); + + // Default title + int x,y; + int space=rfull.h/20; + w_title=new Printer(); + w_title->SetFontSize(space*2); + w_title->SetFontColor(Cfg::Color::DialogHeader); + w_title->Autosize("Exit game?"); + w_title->Print("Exit game?",0); + x=(rfull.w-w_title->GetWidth())/2; + y=rfull.h/4; + w_title->Move(x,y); + AddWidget(w_title); + + // the buttons + int w=rfull.w/4; + int h=20; + x=rfull.w/2; + y=(rfull.h/4)*3; + w_ok=new BitmapButton(); + w_ok->Move(x-(w+space),y); + w_ok->Resize(w,h); + w_ok->SetCaption("OK"); + w_cancel=new BitmapButton(); + w_cancel->Move(x+space,y); + w_cancel->Resize(w,h); + w_cancel->SetCaption("Cancel"); + AddWidget(w_ok); + AddWidget(w_cancel); + + // Prevent dialog from loading multiple times + if(showing){ + engine->EventGameShutdown(); + } + else{ + showing=true; + } +} + +StdHalt::~StdHalt(){ + DestroyWidgets(); + showing=false; +} + +bool StdHalt::InputOk(Widget *Object){ + bool retval=false; + if(Object==w_ok){ + // Close dialog + engine->DestroyWidget(this); + engine->EventGameShutdown(); + retval=true; + } + if(Object==w_cancel){ + // Close dialog + engine->DestroyWidget(this); + retval=true; + } + return retval; +} + diff --git a/engines/vileVN/dialogs/stdhalt.h b/engines/vileVN/dialogs/stdhalt.h new file mode 100644 index 0000000000..3e032fb08a --- /dev/null +++ b/engines/vileVN/dialogs/stdhalt.h @@ -0,0 +1,27 @@ +/*! \class StdHalt + * \brief Standard dialog to confirm that the user wants to exit + */ +#ifndef _STDHALT_H_ +#define _STDHALT_H_ + +#include "dlgbase.h" + +class StdHalt : public DialogBase { + private: + // Flags wether dialog is already showning + static bool showing; + protected: + // Dialog widgets + Printer *w_title; + BitmapButton *w_ok; + BitmapButton *w_cancel; + + // Override events + virtual bool InputOk(Widget *Object); + public: + StdHalt(EngineVN *Engine); + ~StdHalt(); +}; + +#endif + diff --git a/engines/vileVN/dialogs/stdload.cpp b/engines/vileVN/dialogs/stdload.cpp new file mode 100644 index 0000000000..9a15688bdc --- /dev/null +++ b/engines/vileVN/dialogs/stdload.cpp @@ -0,0 +1,42 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "stdload.h" +#include "../engine/evn.h" + +StdLoad::StdLoad(EngineVN *Engine) : StdSave(Engine){ + // Change title + w_title->Clear(); + w_title->Autosize("Load"); + w_title->Print("Load",0); +} + +/*! \brief Override save event to load instead + * \param Index Integer for naming the game + */ +void StdLoad::Save(int Index){ + Load(Index); +} + +/*! \brief Load game + * \param Index Integer for naming the game + */ +void StdLoad::Load(int Index){ + if(engine->EventLoad(Index)){ + engine->DestroyWidget(this); + engine->SetTransition(); + } +} + diff --git a/engines/vileVN/dialogs/stdload.h b/engines/vileVN/dialogs/stdload.h new file mode 100644 index 0000000000..e9f2a3b6b1 --- /dev/null +++ b/engines/vileVN/dialogs/stdload.h @@ -0,0 +1,18 @@ +/*! \class StdLoad + * \brief Standard (ie. simple!) save dialog + */ +#ifndef _STDLOAD_H_ +#define _STDLOAD_H_ + +#include "stdsave.h" + +class StdLoad : public StdSave { + private: + virtual void Save(int Index); + public: + StdLoad(EngineVN *Engine); + virtual void Load(int Index); +}; + +#endif + diff --git a/engines/vileVN/dialogs/stdmenu.cpp b/engines/vileVN/dialogs/stdmenu.cpp new file mode 100644 index 0000000000..3021a7df38 --- /dev/null +++ b/engines/vileVN/dialogs/stdmenu.cpp @@ -0,0 +1,121 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "stdmenu.h" +#include "../engine/evn.h" + +StdMenu::StdMenu(EngineVN *Engine) : DialogBase(Engine,false){ + int w=Engine->NativeWidth()/SI_ITEM_COUNT; + int y=2; + int x=10; + w_items[SI_NEW]=new TextButton(x+(w*0),y,"New"); + w_items[SI_LOAD]=new TextButton(x+(w*1),y,"Load"); + w_items[SI_SAVE]=new TextButton(x+(w*2),y,"Save"); + w_items[SI_OPTIONS]=new TextButton(x+(w*3),y,"Options"); + w_items[SI_TITLE]=new TextButton(x+(w*4),y,"Title"); + w_items[SI_EXIT]=new TextButton(x+(w*5),y,"Exit"); + Uint32 hover=0x000000FF; + Uint32 normal=0x7F7F7FFF; + for(int i=0;iSetColorForeground(WS_NORMAL,normal); + w_items[i]->SetColorForeground(WS_HOVER,hover); + w_items[i]->FocusEnter(); + w_items[i]->FocusLeave(); + AddWidget(w_items[i]); + } + + // Create base graphics + Resize(Engine->NativeWidth(),w_items[SI_NEW]->GetHeight()+(y*2)); + Fill(0xFF,0xFF,0xFF,0xFF); + s_gfx=EDL_CreateSurface(simage->w,simage->h); + EDL_BlitSurface(simage,0,s_gfx,0); + + // Hide dialog + visible=true; + ShowMenu(false); +} + +StdMenu::~StdMenu(){ + DestroyWidgets(); + SDL_FreeSurface(s_gfx); +} + +/*! \brief Shows or hides the menu + * \param Visible True to show, false to hide + */ +void StdMenu::ShowMenu(bool Visible){ + if(Visible!=visible){ + visible=Visible; + w_items[SI_NEW]->SetVisible(Visible); + w_items[SI_LOAD]->SetVisible(Visible); + w_items[SI_SAVE]->SetVisible(Visible); + w_items[SI_OPTIONS]->SetVisible(Visible); + w_items[SI_TITLE]->SetVisible(Visible); + w_items[SI_EXIT]->SetVisible(Visible); + if(Visible){ + Blit(s_gfx); + } + else{ + Free(); + } + } +} + +/*! \brief Overrides event to automatically show the dropdown menu + * \return Value from DialogBase + */ +bool StdMenu::FocusEnter(){ + if(!visible){ + ShowMenu(true); + } + return DialogBase::FocusEnter(); +} + +/*! \brief Overrides event to automatically hide the dropdown menu + * \return Value from DialogBase + */ +bool StdMenu::FocusLeave(){ + if(visible){ + ShowMenu(false); + } + return DialogBase::FocusLeave(); +} + +/*! \brief Hook user input and generate appropriate engine events + * \param Object Clicked widget + * \return Always true + */ +bool StdMenu::InputOk(Widget *Object){ + if(Object==w_items[SI_NEW]){ + engine->EventNew(); + } + if(Object==w_items[SI_LOAD]){ + engine->EventGameDialog(VD_LOAD); + } + if(Object==w_items[SI_SAVE]){ + engine->EventGameDialog(VD_SAVE); + } + if(Object==w_items[SI_OPTIONS]){ + engine->EventGameDialog(VD_OPTIONS); + } + if(Object==w_items[SI_TITLE]){ + engine->EventGameDialog(VD_TITLE); + } + if(Object==w_items[SI_EXIT]){ + engine->EventGameDialog(VD_SHUTDOWN); + } + return true; +} + diff --git a/engines/vileVN/dialogs/stdmenu.h b/engines/vileVN/dialogs/stdmenu.h new file mode 100644 index 0000000000..96774d2f06 --- /dev/null +++ b/engines/vileVN/dialogs/stdmenu.h @@ -0,0 +1,39 @@ +/*! \class StdMenu + * \brief Standard (ie. simple!) drop down menu + */ +#ifndef _STDMENU_H_ +#define _STDMENU_H_ + +#include "dlgbase.h" + +enum STDMENU_ITEMS { + SI_NEW, + SI_LOAD, + SI_SAVE, + SI_OPTIONS, + SI_TITLE, + SI_EXIT, + SI_ITEM_COUNT +}; + +class StdMenu : public DialogBase { + protected: + // Dialog widgets + TextButton *w_items[SI_ITEM_COUNT]; + SDL_Surface *s_gfx; + bool visible; + + // Helpers + void ShowMenu(bool Visible); + + // Override events + virtual bool InputOk(Widget *Object); + virtual bool FocusEnter(); + virtual bool FocusLeave(); + public: + StdMenu(EngineVN *Engine); + ~StdMenu(); +}; + +#endif + diff --git a/engines/vileVN/dialogs/stdmsg.cpp b/engines/vileVN/dialogs/stdmsg.cpp new file mode 100644 index 0000000000..1906393220 --- /dev/null +++ b/engines/vileVN/dialogs/stdmsg.cpp @@ -0,0 +1,90 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "stdmsg.h" +#include "../engine/evn.h" + +StdMessage::StdMessage(EngineVN *Engine,uString Title,uString Message) + : DialogBase(Engine,true){ + // Create background graphics + SDL_Rect rfull={0,0,Engine->NativeWidth(),Engine->NativeHeight()}; + Move(rfull); + Fill(Cfg::Color::DialogBackground); + + // Set title + int x,y; + int space=rfull.h/20; + if(Title.length()){ + w_title=new Printer(); + w_title->SetFontSize(space*2); + w_title->SetFontColor(Cfg::Color::DialogHeader); + w_title->Autosize(Title); + w_title->Print(Title,0); + x=(rfull.w-w_title->GetWidth())/2; + y=rfull.h/6; + w_title->Move(x,y); + AddWidget(w_title); + } + else{ + w_title=0; + } + + // Create message + w_message=new Printer(); + w_message->SetFontSize(space); + w_message->SetFontColor(Cfg::Color::DialogTopic); + if(w_title){ + w_message->Move(space*2,w_title->GetY()+w_title->GetHeight()+space); + w_message->Resize(rfull.w-(space*4),rfull.h-(space*8)); + } + else{ + w_message->Move(space*2,space*2); + w_message->Resize(rfull.w-(space*4),rfull.h-(space*8)); + } + w_message->Print(Message,0); + AddWidget(w_message); + + // Add a button + int w=rfull.w-(space*2); + int h=20; + x=space; + y=rfull.h-(h+space); + if(EDL_ReadableFile(Cfg::Path::resource)){ + BitmapButton *w_tmp=new BitmapButton(); + w_tmp->Move(x,y); + w_tmp->Resize(w,h); + w_tmp->SetCaption("OK"); + w_ok=w_tmp; + } + else{ + w_ok=new TextButton(x,y,w,h,"OK"); + } + AddWidget(w_ok); +} + +StdMessage::~StdMessage(){ + DestroyWidgets(); +} + +bool StdMessage::InputOk(Widget *Object){ + bool retval=false; + if(Object==w_ok){ + // Close dialog + engine->DestroyWidget(this); + retval=true; + } + return retval; +} + diff --git a/engines/vileVN/dialogs/stdmsg.h b/engines/vileVN/dialogs/stdmsg.h new file mode 100644 index 0000000000..307677aaf9 --- /dev/null +++ b/engines/vileVN/dialogs/stdmsg.h @@ -0,0 +1,24 @@ +/*! \class StdMessage + * \brief Presents a message + */ +#ifndef _STDMSG_H_ +#define _STDMSG_H_ + +#include "dlgbase.h" + +class StdMessage : public DialogBase { + protected: + // Dialog widgets + Printer *w_title; + Printer *w_message; + Widget *w_ok; + + // Override events + virtual bool InputOk(Widget *Object); + public: + StdMessage(EngineVN *Engine,uString Title,uString Message); + ~StdMessage(); +}; + +#endif + diff --git a/engines/vileVN/dialogs/stdsave.cpp b/engines/vileVN/dialogs/stdsave.cpp new file mode 100644 index 0000000000..5fa8d6a8e3 --- /dev/null +++ b/engines/vileVN/dialogs/stdsave.cpp @@ -0,0 +1,240 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "stdsave.h" +#include "../engine/evn.h" + +StdSave::StdSave(EngineVN *Engine) : DialogBase(Engine,true){ + // Create background graphics + SDL_Rect rfull={0,0,Engine->NativeWidth(),Engine->NativeHeight()}; + Move(rfull); + Fill(0x00,0x00,0x00,200); + + // Default title + int space=rfull.h/20; + w_title=new Printer(); + w_title->Move(space,space); + w_title->SetFontSize(space*2); + w_title->SetFontColor(100,0,0); + w_title->Autosize("Save"); + w_title->Print("Save",0); + AddWidget(w_title); + + // the exit button + w_exit=new TextButton((rfull.w/10)*9,rfull.h-(space*2),"Exit"); + AddWidget(w_exit); + + // Create saveslab widgets + int y1=w_title->GetY()+w_title->GetHeight()+space; + int y2=w_exit->GetY()-space; + int yh=(y2-y1)/4; + int yw=(rfull.w/2)-(space*2); + for(int i=0;i<4;i++){ + w_slabs[i]=new SaveSlab(space,y1+(yh*i)+(i*2),yw,yh); + AddWidget(w_slabs[i]); + w_slabs[i+4]=new SaveSlab((rfull.w/2)+space,y1+(yh*i)+(i*2),yw,yh); + AddWidget(w_slabs[i+4]); + } + + // Create page buttons + int x1=w_title->GetX()+w_title->GetWidth()+space; + int x2=rfull.w-space; + int xd=(x2-x1)/5; + y1=w_title->GetY()+(w_title->GetHeight()/3); + w_pages[0]=new TextButton(x1+(xd*0),y1,"Page 1"); + w_pages[1]=new TextButton(x1+(xd*1),y1,"Page 2"); + w_pages[2]=new TextButton(x1+(xd*2),y1,"Page 3"); + w_pages[3]=new TextButton(x1+(xd*3),y1,"Page 4"); + w_pages[4]=new TextButton(x1+(xd*4),y1,"Page 5"); + AddWidget(w_pages[0]); + AddWidget(w_pages[1]); + AddWidget(w_pages[2]); + AddWidget(w_pages[3]); + AddWidget(w_pages[4]); + + // Set defaults + page=-1; + SetPage(0); +} + +StdSave::~StdSave(){ + DestroyWidgets(); +} + +/*! \brief Sets title string to be displayed + * \param Caption Text to set + */ +void StdSave::SetCaption(uString Caption){ + w_title->Clear(); + w_title->Print(Caption,0); + Refresh(); +} + +/*! \brief Event to signal clicking of a saveslab + * \param Index Integer for naming the game + */ +void StdSave::Save(int Index){ + if(engine->EventSave(Index)){ + engine->DestroyWidget(this); + engine->SetTransition(); + } +} + +/*! \brief Displays a given page of the dialog + * \param Page Page to display (0-4 for page 1-5) + */ +void StdSave::SetPage(int Page){ + if(Page!=page){ + // Register new page + Refresh(); + page=Page; + + // Change paginators + Uint32 fore=0xFFFFFFFF; + Uint32 back=0x000000FF; + for(int i=0;i<5;i++){ + w_pages[i]->SetColorForeground(WS_NORMAL,back); + w_pages[i]->FocusEnter(); + w_pages[i]->FocusLeave(); + } + w_pages[page]->SetColorForeground(WS_NORMAL,fore); + w_pages[page]->FocusEnter(); + + + // Change savegame slabs + for(int i=0;i<8;i++){ + // Flush slab graphic and create background + w_slabs[i]->Flush(); + SDL_Surface *savebg=EDL_CreateSurface( + w_slabs[i]->GetWidth(), + w_slabs[i]->GetHeight()); + boxRGBA(savebg,0,0,savebg->w,savebg->h,0xFF,0xFF,0xFF,0x9F); + w_slabs[i]->SetBackground(savebg,0); + SDL_FreeSurface(savebg); + + // Load data from savefile + Savegame save(engine->NativeID(),(page*8)+i); + if(save.Read()){ + int space=5; + int h=w_slabs[i]->GetHeight()-(space*2); + double r=engine->NativeWidth()/(double)engine->NativeHeight(); + SDL_Surface *screen=0; + if(save.LoadSurface("screen-thumb",&screen,h*r,h)){ + // Set thumbview + SDL_Rect dst={space,space,screen->w,screen->h}; + w_slabs[i]->SetThumb(screen,0,&dst); + SDL_FreeSurface(screen); + + // Set highlight + SDL_Surface *hl=EDL_CreateSurface( + w_slabs[i]->GetWidth(), + w_slabs[i]->GetHeight()); + boxRGBA(hl,0,0,hl->w,hl->h,0x00,0x00,0x00,0x00); + rectangleRGBA(hl,0,0,hl->w,hl->h,0xFF,0,0,0xFF); + w_slabs[i]->SetOverlay(hl,&dst); + SDL_FreeSurface(hl); + + // Set saveinfo + EDL_SETRECT(dst,(h*r)+(space*2),space, + w_slabs[i]->GetWidth()-(h*r)-(space*3), + w_slabs[i]->GetHeight()-(space*2)); + uString tmpstr="Unknown"; + save.LoadString("savemsg",&tmpstr); + uString msgstr=tmpstr+"\n"; + save.LoadString("savedate",&tmpstr); + msgstr+=tmpstr; + w_slabs[i]->SetText(msgstr,&dst); + } + } + } + } +} + +/*! \brief Highlights the focused saveslab by adjusting the background alpha + */ +bool StdSave::FocusEnter(Widget *Object){ + bool retval=Object==w_slabs[0] || Object==w_slabs[1] || + Object==w_slabs[2] || Object==w_slabs[3] || + Object==w_slabs[4] || Object==w_slabs[5] || + Object==w_slabs[6] || Object==w_slabs[7]; + if(retval){ + ((SaveSlab*)Object)->SetBackgroundAlpha(0xFF); + Refresh(); + } + return retval; +} + +/*! \brief Removes highlight from the previously focused saveslab + */ +bool StdSave::FocusLeave(Widget *Object){ + bool retval=Object==w_slabs[0] || Object==w_slabs[1] || + Object==w_slabs[2] || Object==w_slabs[3] || + Object==w_slabs[4] || Object==w_slabs[5] || + Object==w_slabs[6] || Object==w_slabs[7]; + if(retval){ + ((SaveSlab*)Object)->SetBackgroundAlpha(0x7F); + Refresh(); + } + return retval; +} + +bool StdSave::InputOk(Widget *Object){ + bool retval=false; + if(Object==w_exit){ + // Close dialog + engine->DestroyWidget(this); + engine->SetTransition(); + retval=true; + } + else if(Object==w_pages[0] || + Object==w_pages[1] || + Object==w_pages[2] || + Object==w_pages[3] || + Object==w_pages[4]){ + // Change page + if(Object==w_pages[0]) SetPage(0); + if(Object==w_pages[1]) SetPage(1); + if(Object==w_pages[2]) SetPage(2); + if(Object==w_pages[3]) SetPage(3); + if(Object==w_pages[4]) SetPage(4); + retval=true; + } + else if(Object==w_slabs[0] || + Object==w_slabs[1] || + Object==w_slabs[2] || + Object==w_slabs[3] || + Object==w_slabs[4] || + Object==w_slabs[5] || + Object==w_slabs[6] || + Object==w_slabs[7]){ + // Get savegame index + int index=-1; + if(Object==w_slabs[0]) index=(page*8)+0; + if(Object==w_slabs[1]) index=(page*8)+1; + if(Object==w_slabs[2]) index=(page*8)+2; + if(Object==w_slabs[3]) index=(page*8)+3; + if(Object==w_slabs[4]) index=(page*8)+4; + if(Object==w_slabs[5]) index=(page*8)+5; + if(Object==w_slabs[6]) index=(page*8)+6; + if(Object==w_slabs[7]) index=(page*8)+7; + + // Save game + if(index!=-1) Save(index); + retval=true; + } + + return retval; +} + diff --git a/engines/vileVN/dialogs/stdsave.h b/engines/vileVN/dialogs/stdsave.h new file mode 100644 index 0000000000..644a8dcd50 --- /dev/null +++ b/engines/vileVN/dialogs/stdsave.h @@ -0,0 +1,33 @@ +/*! \class StdSave + * \brief Standard (ie. simple!) save dialog + */ +#ifndef _STDSAVE_H_ +#define _STDSAVE_H_ + +#include "dlgbase.h" + +class StdSave : public DialogBase { + protected: + // Dialog widgets + SaveSlab *w_slabs[8]; + TextButton *w_pages[5]; + TextButton *w_exit; + Printer *w_title; + int page; + + // Override events + virtual bool InputOk(Widget *Object); + virtual bool FocusEnter(Widget *Object); + virtual bool FocusLeave(Widget *Object); + public: + StdSave(EngineVN *Engine); + ~StdSave(); + + // Autonomous events + void SetCaption(uString Caption); + virtual void SetPage(int Page); + virtual void Save(int Index); +}; + +#endif + diff --git a/engines/vileVN/dialogs/stdtitle.cpp b/engines/vileVN/dialogs/stdtitle.cpp new file mode 100644 index 0000000000..d14642b95b --- /dev/null +++ b/engines/vileVN/dialogs/stdtitle.cpp @@ -0,0 +1,154 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "stdtitle.h" +#include "../engine/evn.h" + +StdTitle::StdTitle(EngineVN *Engine) : DialogBase(Engine,true) { + // Set defaults + w_new_button=0; + w_load_button=0; + w_option_button=0; + w_extra_button=0; + w_exit_button=0; + w_resume_button=0; + + // Adjust to the engine + Resize(Engine->NativeWidth(),Engine->NativeHeight()); +} + +StdTitle::~StdTitle(){ +} + +/*! \brief Assign button for starting a new game + * \param Object Preconfigured button widget + */ +void StdTitle::SetNewButton(BitmapButton *Object){ + w_new_button=Object; + AddWidget(Object); +} + +/*! \brief Assign button for accessing the load screen + * \param Object Preconfigured button widget + */ +void StdTitle::SetLoadButton(BitmapButton *Object){ + w_load_button=Object; + AddWidget(Object); +} + +/*! \brief Assign button for accessing the option screen + * \param Object Preconfigured button widget + */ +void StdTitle::SetOptionButton(BitmapButton *Object){ + w_option_button=Object; + AddWidget(Object); +} + +/*! \brief Assign button for accessing the extras screen + * \param Object Preconfigured button widget + */ +void StdTitle::SetExtraButton(BitmapButton *Object){ + w_extra_button=Object; + AddWidget(Object); +} + +/*! \brief Assign button for accessing the extras screen + * \param Object Preconfigured button widget + */ +void StdTitle::SetExtraCGButton(BitmapButton *Object){ + w_extra_cg_button=Object; + AddWidget(Object); +} + +/*! \brief Assign button for accessing the extras screen + * \param Object Preconfigured button widget + */ +void StdTitle::SetExtraBGMButton(BitmapButton *Object){ + w_extra_bgm_button=Object; + AddWidget(Object); +} + +/*! \brief Assign button for accessing the extras screen + * \param Object Preconfigured button widget + */ +void StdTitle::SetExtraSceneButton(BitmapButton *Object){ + w_extra_scene_button=Object; + AddWidget(Object); +} + +/*! \brief Assign button for exiting the application + * \param Object Preconfigured button widget + */ +void StdTitle::SetExitButton(BitmapButton *Object){ + w_exit_button=Object; + AddWidget(Object); +} + +/*! \brief Assign button for hiding the title screen + * \param Object Preconfigured button widget + */ +void StdTitle::SetResumeButton(BitmapButton *Object){ + w_resume_button=Object; + AddWidget(Object); +} + +/*! \brief Overrides mouse click events + * \param Widget The selected widget object + * \return True if event was handled + */ +bool StdTitle::InputOk(Widget *Object){ + bool retval=true; + if(Object==w_new_button){ + // Generate savebutton event and hide dialog + engine->EventNew(); + } + else if(Object==w_load_button){ + // Generate loadbutton event + engine->EventGameDialog(VD_LOAD); + } + else if(Object==w_option_button){ + // Generate optionbutton event + engine->EventGameDialog(VD_OPTIONS); + } + else if(Object==w_extra_button){ + // Generate optionbutton event + engine->EventGameDialog(VD_EXTRAS); + } + else if(Object==w_extra_cg_button){ + // Generate optionbutton event + engine->EventGameDialog(VD_EXTRAS_CG); + } + else if(Object==w_extra_bgm_button){ + // Generate optionbutton event + engine->EventGameDialog(VD_EXTRAS_BGM); + } + else if(Object==w_extra_scene_button){ + // Generate optionbutton event + engine->EventGameDialog(VD_EXTRAS_SCENE); + } + else if(Object==w_exit_button){ + // Generate optionbutton event + engine->EventGameDialog(VD_SHUTDOWN); + } + else if(Object==w_resume_button){ + // Generate optionbutton event + SetVisible(false); + } + else{ + retval=false; + } + return retval; +} + diff --git a/engines/vileVN/dialogs/stdtitle.h b/engines/vileVN/dialogs/stdtitle.h new file mode 100644 index 0000000000..37c5a69293 --- /dev/null +++ b/engines/vileVN/dialogs/stdtitle.h @@ -0,0 +1,47 @@ +/*! \class StdTitle + * \brief Widget for managing a textview with buttons + * + * This should only be used as a basis for complex textview object which + * has embedded buttons etc. You should just use a Printer object if all + * you need is the animated text. + * + * This class must be revised from bottom up. + */ +#ifndef _STDTITLE_H_ +#define _STDTITLE_H_ + +#include "dlgbase.h" + +class StdTitle : public DialogBase { + private: + // Standard widgets + BitmapButton *w_new_button; + BitmapButton *w_load_button; + BitmapButton *w_option_button; + BitmapButton *w_extra_button; + BitmapButton *w_extra_cg_button; + BitmapButton *w_extra_bgm_button; + BitmapButton *w_extra_scene_button; + BitmapButton *w_exit_button; + BitmapButton *w_resume_button; + + // Hook into user input + virtual bool InputOk(Widget *Object); + public: + StdTitle(EngineVN *Engine); + ~StdTitle(); + + // Register standard buttons + void SetNewButton(BitmapButton *Object); + void SetLoadButton(BitmapButton *Object); + void SetOptionButton(BitmapButton *Object); + void SetExtraButton(BitmapButton *Object); + void SetExtraCGButton(BitmapButton *Object); + void SetExtraBGMButton(BitmapButton *Object); + void SetExtraSceneButton(BitmapButton *Object); + void SetExitButton(BitmapButton *Object); + void SetResumeButton(BitmapButton *Object); +}; + +#endif + diff --git a/engines/vileVN/dialogs/textview.cpp b/engines/vileVN/dialogs/textview.cpp new file mode 100644 index 0000000000..2f2d81968a --- /dev/null +++ b/engines/vileVN/dialogs/textview.cpp @@ -0,0 +1,289 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "textview.h" +#include "../engine/evn.h" + +Textview::Textview(EngineVN *Engine) : DialogBase(Engine,false) { + // Set defaults + w_text=0; + w_savebutton=0; + w_loadbutton=0; + w_optionbutton=0; + w_backbutton=0; + w_skipbutton=0; + w_autobutton=0; + textlog_flag=true; + xdisplacement=0; + ydisplacement=0; + + // Always allocate text widget + w_text=new Printer(); + w_text->SetFontColor(0xFF,0xFF,0xFF); + AddWidget(w_text); +} + +Textview::~Textview(){ + uString *object; + while((object=(uString*)textlog_stack.Pop())){ + delete object; + } +} + +void Textview::SetSkipmode(bool Skip){ + if(w_skipbutton){ + w_skipbutton->SetValue(Skip); + } +} + +bool Textview::GetSkipmode(){ + if(w_skipbutton){ + return w_skipbutton->GetValue(); + } + else{ + return false; + } +} + +void Textview::SetSaveButton(BitmapButton *Object){ + w_savebutton=Object; + AddWidget(Object); +} + +void Textview::SetLoadButton(BitmapButton *Object){ + w_loadbutton=Object; + AddWidget(Object); +} + +void Textview::SetSkipButton(ValueButton *Object){ + w_skipbutton=Object; + AddWidget(Object); +} + +void Textview::SetAutoButton(BitmapButton *Object){ + w_autobutton=Object; + AddWidget(Object); +} + +void Textview::SetOptionButton(BitmapButton *Object){ + w_optionbutton=Object; + AddWidget(Object); +} + +void Textview::SetBackButton(BitmapButton *Object){ + w_backbutton=Object; + AddWidget(Object); +} + +bool Textview::GetTextPosition(int *X,int *Y,int *W,int *H){ + if(w_text){ + *X=w_text->GetX(); + *Y=w_text->GetY(); + *W=w_text->GetWidth(); + *H=w_text->GetHeight(); + } + return w_text; +} + +void Textview::SetTextPosition(int X,int Y,int W,int H){ + if(w_text){ + w_text->Move(X,Y); + w_text->Resize(W,H); + xdisplacement=0; + ydisplacement=0; + } +} + +void Textview::SetTextInterval(Uint32 Milliseconds){ + if(w_text){ + w_text->SetInterval(Milliseconds); + } +} + +void Textview::CompleteText(){ + if(w_text){ + w_text->SkipScreen(); + } +} + +void Textview::ClearText(){ + if(w_text){ + if(textlog_flag){ + uString *object=(uString*)textlog_stack.Pop(); + if(object && object->length()){ + textlog_stack.Push(object); + } + else{ + delete object; + } + textlog_stack.Push(new uString); + if(textlog_stack.Count()>TEXLOG_LINES){ + uString *s=(uString*)textlog_stack.Drop( + textlog_stack.Count()-1); + delete s; + } + } + w_text->Clear(); + } +} + +void Textview::PrintNewline(){ + if(w_text){ + if(textlog_flag){ + uString *object=(uString*)textlog_stack.Pop(); + if(!object){ + object=new uString; + } + *object+="\n"; + textlog_stack.Push(object); + } + w_text->Newline(); + } +} + +void Textview::PrintText(uString Title,uString Text){ + if(w_text){ + uString newstring="["; + newstring+=Title; + newstring+="]\n"; + newstring+=Text; + PrintText(newstring); + } +} + +void Textview::PrintText(uString Text){ + if(w_text){ + if(textlog_flag){ + uString *object=(uString*)textlog_stack.Pop(); + if(!object){ + object=new uString; + } + *object+=Text; + textlog_stack.Push(object); + } + int delay=0; + if(engine->GetMessageDelayEnabled()){ + delay=engine->GetMessageDelayInterval(); + } + w_text->Print(Text,delay); + } +} + +int Textview::GetRemainingText(){ + if(w_text){ + return w_text->GetRemaining(); + } + else{ + return 0; + } +} + +void Textview::EnableTextlog(bool Enable){ + textlog_flag=Enable; +} + +uString Textview::GetTextlog(int Index){ + uString *retval=(uString*)textlog_stack.Get(Index); + if(retval){ + return *retval; + } + else{ + return ""; + } +} + +bool Textview::GetTextSize(uString Text,int *Width,int *Height){ + if(w_text){ + return w_text->GetTextSize(Text,Width,Height); + } + else{ + return false; + } +} + +void Textview::SetFontFace(uString Filename){ + if(w_text){ + w_text->SetFontFace(Filename); + } +} + +void Textview::SetFontSize(int Size){ + if(w_text){ + w_text->SetFontSize(Size); + } +} + +void Textview::SetFontColor(Uint8 Red,Uint8 Green,Uint8 Blue){ + if(w_text){ + w_text->SetFontColor(Red,Green,Blue); + } +} + +void Textview::SetFontColor(SDL_Color Color){ + if(w_text){ + w_text->SetFontColor(Color); + } +} + +void Textview::SetFontStyle(int Style){ + if(w_text){ + w_text->SetFontStyle(Style); + } +} + +void Textview::SetFontShadow(int X,int Y,SDL_Color Color){ + if(w_text){ + w_text->SetFontShadow(X,Y,Color); + } +} + +void Textview::SetFontGlow(int Glow,SDL_Color Color){ + if(w_text){ + w_text->SetFontGlow(Glow,Color); + } +} + +/*! \brief Overrides mouse click events, id clicked widget and generates event + */ +bool Textview::InputOk(Widget *Object){ + bool retval=false; + if(Object==w_savebutton){ + // Generate savebutton event + engine->EventGameDialog(VD_SAVE); + retval=true; + } + else if(Object==w_loadbutton){ + // Generate loadbutton event + engine->EventGameDialog(VD_LOAD); + retval=true; + } + else if(Object==w_optionbutton){ + // Generate optionbutton event + engine->EventGameDialog(VD_OPTIONS); + retval=true; + } + else if(Object==w_backbutton){ + retval=true; + } + else if(Object==w_skipbutton){ + engine->SetSkipmode(!GetSkipmode()); + retval=true; + } + else if(Object==w_autobutton){ + retval=true; + } + return retval; +} + diff --git a/engines/vileVN/dialogs/textview.h b/engines/vileVN/dialogs/textview.h new file mode 100644 index 0000000000..f7fc25829b --- /dev/null +++ b/engines/vileVN/dialogs/textview.h @@ -0,0 +1,79 @@ +/*! \class Textview + * \brief Widget for managing a textview with buttons + * + * This should only be used as a basis for complex textview object which + * has embedded buttons etc. You should just use a Printer object if all + * you need is the animated text. + * + * This class must be revised from bottom up. + */ +#ifndef _TEXTVIEW_H_ +#define _TEXTVIEW_H_ + +#include "dlgbase.h" + +#define TEXLOG_LINES 100 //!< Number of lines to store in log + +class Textview : public DialogBase { + private: + // Standard widgets + Printer *w_text; + ValueButton *w_skipbutton; + BitmapButton *w_savebutton; + BitmapButton *w_loadbutton; + BitmapButton *w_optionbutton; + BitmapButton *w_backbutton; + BitmapButton *w_autobutton; + + // Textlogging + bool textlog_flag; + DStack textlog_stack; + + // Other data + int xdisplacement; + int ydisplacement; + public: + Textview(EngineVN *Engine); + ~Textview(); + + // API + virtual void PrintText(uString Title,uString Text); + virtual void PrintText(uString Text); + virtual void PrintNewline(); + virtual void CompleteText(); + virtual void ClearText(); + bool GetTextSize(uString Text,int *Width,int *Height); + bool GetTextPosition(int *X,int *Y,int *W,int *H); + void SetTextPosition(int X,int Y,int W,int H); + void SetTextInterval(Uint32 Milliseconds); + void SetFontFace(uString Filename); + void SetFontSize(int Size); + void SetFontColor(Uint8 Red,Uint8 Green,Uint8 Blue); + void SetFontColor(SDL_Color Color); + void SetFontStyle(int Style); + void SetFontShadow(int X,int Y,SDL_Color Color); + void SetFontGlow(int Glow,SDL_Color Color); + int GetRemainingText(); + + // Log feature + uString GetTextlog(int Index); + void EnableTextlog(bool Enable); + + // Set skipmode + void SetSkipmode(bool Skip); + bool GetSkipmode(); + + // Register standard buttons + void SetSaveButton(BitmapButton *Object); + void SetLoadButton(BitmapButton *Object); + void SetSkipButton(ValueButton *Object); + void SetAutoButton(BitmapButton *Object); + void SetOptionButton(BitmapButton *Object); + void SetBackButton(BitmapButton *Object); + + // Hook into user input + virtual bool InputOk(Widget *Object); +}; + +#endif + diff --git a/engines/vileVN/engine/crenderer.cpp b/engines/vileVN/engine/crenderer.cpp new file mode 100644 index 0000000000..7fdcd00856 --- /dev/null +++ b/engines/vileVN/engine/crenderer.cpp @@ -0,0 +1,123 @@ +#include "crenderer.h" + +CachedRenderer::CachedRenderer(Group *Widgets,Group *Animations,int Width, + int Height) : Renderer(Widgets,Animations,Width,Height) { + clean=0; + cleanhash=0; +} + +CachedRenderer::~CachedRenderer() { + if(clean){ + SDL_FreeSurface(clean); + } +} + +/*! \brief Renders tainted widgets on top of a hashed cache + * \param Surface Surface to render to + */ +void CachedRenderer::UpdateWidgets(SDL_Surface *Surface){ + // Reset global refresh while checking it + if(!Widget::GetGlobalRefresh()){ + LogError("Renderer called unneccessary"); + } + + // Find first visible layer + int layer=widgets->GetGroupCount()-1; + Group *gptr=widgets->GetGroup(layer); + Widget *wptr=0; + Group *bottomg=0; + Widget *bottomw=0; + while(gptr){ + wptr=gptr->GetWidget(gptr->GetWidgetCount()-1); + while(wptr){ + if(wptr->GetVisible()){ + SDL_Rect r=wptr->GetPosition(); + if(!r.x && !r.y && r.w>=width && r.h>=height){ + if(wptr->TestSolid()){ + bottomg=gptr; + bottomw=wptr; + } + } + } + wptr=wptr->PrevPtr; + } + gptr=gptr->PrevPtr; + layer--; + } + if(!bottomg){ + bottomg=widgets->GetGroup(widgets->GetGroupCount()-1); + bottomw=bottomg->GetWidget(bottomg->GetWidgetCount()-1); + } + + // Calculate hash and validate cache + if(clean){ + Uint32 hash=0; + gptr=bottomg; + wptr=bottomw; + do{ + while(wptr){ + if(wptr->GetVisible() && !wptr->PeekLocalRefresh()){ + hash=EDL_HashUpdate(hash,wptr); + } + wptr=wptr->PrevPtr; + } + gptr=gptr->PrevPtr; + if(gptr){ + wptr=gptr->GetWidget(gptr->GetWidgetCount()-1); + } + }while(gptr); + if(hash!=cleanhash){ +LogError("HASH:%08X:%08X"); + cleanhash=hash; + SDL_FreeSurface(clean); + clean=0; + } + } + + // Assert cache and paint it to the surface + if(!clean){ + gptr=bottomg; + wptr=bottomw; + do{ + while(wptr){ + if(wptr->GetVisible() && !wptr->PeekLocalRefresh()){ + if(!clean){ + clean=EDL_CreateSurface(width,height); + } +LogTest("Caching clean widget: %dx%d",wptr->GetWidth(),wptr->GetHeight()); +EDL_SetAlpha(clean,0,0xFF); + wptr->Copy(clean); + } + wptr=wptr->PrevPtr; + } + gptr=gptr->PrevPtr; + if(gptr){ + wptr=gptr->GetWidget(gptr->GetWidgetCount()-1); + } + }while(gptr); + } + if(clean){ + EDL_BlitSurface(clean,0,Surface,0); +EDL_SetAlpha(Surface,0,0xFF); + } + + // Paint dirty widgets to the surface + gptr=bottomg; + wptr=bottomw; + do{ + while(wptr){ + if(wptr->GetVisible() && wptr->GetLocalRefresh()){ +LogTest("Blitting dirty widget: %u=%dx%d",wptr,wptr->GetWidth(),wptr->GetHeight()); +EDL_SetAlpha(Surface,0,0xFF); + wptr->Copy(Surface); + } + wptr=wptr->PrevPtr; + } + gptr=gptr->PrevPtr; + if(gptr){ + wptr=gptr->GetWidget(gptr->GetWidgetCount()-1); + } + }while(gptr); +EDL_SetAlpha(Surface,0,0xFF); +} + diff --git a/engines/vileVN/engine/crenderer.h b/engines/vileVN/engine/crenderer.h new file mode 100644 index 0000000000..f4199e310b --- /dev/null +++ b/engines/vileVN/engine/crenderer.h @@ -0,0 +1,36 @@ +/*! \class CachedRenderer + * \brief Renders widgets onto a surface using an internal cache + * + * The idea of the CachedRenderer is that most games layers a background, + * some character graphics and a textview widget, whereas most of the time, + * the only screen update is a character changing on the textview widget so + * you do not really have to keep repainting the background or alpha-blending + * the character images. + * + * The CacheRenderer remembers which widgets that requires updates, and + * caches a copy of the static widgets instead of drawing them. The effiency + * of this method depends on the engine implementation, complex systems + * like Ikura usually caches its own graphics on a single surface and will + * not benefit from this at all, but the overhead should be minimal so it + * might be a fair comprimise. + */ + +#ifndef _CRENDERER_H_ +#define _CRENDERER_H_ + +#include "renderer.h" + +class CachedRenderer : public Renderer { + private: + SDL_Surface *clean; + Uint32 cleanhash; + public: + CachedRenderer(Group *Widgets,Group *Animations,int Width,int Height); + ~CachedRenderer(); + + // Optimized functions + virtual void UpdateWidgets(SDL_Surface *Surface); +}; + +#endif + diff --git a/engines/vileVN/engine/ebase.cpp b/engines/vileVN/engine/ebase.cpp new file mode 100644 index 0000000000..2e7efba0cc --- /dev/null +++ b/engines/vileVN/engine/ebase.cpp @@ -0,0 +1,970 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "ebase.h" + +/*! \brief Prepares game surface and other primitives + * \param Width The games native width + * \param Height The games native height + */ +EngineBase::EngineBase(int Width,int Height){ + // Store metrics + width=Width; + height=Height; + + // Load core group + widget_head=new Group(0); + animations=new Group(0); + widget_focus=0; + + // Set defaults + hidemouse=0; + fullscreen=false; + shutdown=false; + transition_type=VT_NONE; + renderer=new Renderer(widget_head,animations,Width,Height); + //renderer=new CachedRenderer(widget_head,Width,Height); +} + +/*! \brief Free objects from ram + */ +EngineBase::~EngineBase(){ + LogVerbose("Closing managed widgets"); + delete renderer; + widget_head->DestroyGroup(); + delete widget_head; + animations->DestroyGroup(); + delete animations; + LogVerbose("Engine is terminated"); +} + +/*! \brief Asserts an indexed layer + * \param Layer Indexed layer + */ +Group *EngineBase::GetLayer(int Layer){ + // Assert layer + while(!widget_head->GetGroup(Layer)){ + new Group(widget_head,Layer); + } + return widget_head->GetGroup(Layer); +} + +/*! \brief Gets an indexed widget + * \param Layer Index of layer to get widget from + * \param Index Index of widget to retrieve + * \returns Indexed widget or NULL if failed + */ +Widget *EngineBase::GetWidget(int Layer,int Index){ + Group *gptr=widget_head->GetGroup(Layer); + if(gptr){ + return gptr->GetWidget(Index); + } + else{ + return 0; + } +} + +/*! \brief Checks wether a widget is still active + * \param WidgetPtr Pointer to widget + * \return True if the widget still exists + */ +bool EngineBase::CheckWidget(Widget *WidgetPtr){ + return widget_head->CheckWidget(WidgetPtr); +} + +/*! \brief Checks wether a shutdown has been confirmed by the user + * \return True if the user has verified a shutdown request + */ +bool EngineBase::GetShutdown(){ + return shutdown; +} + +/*! \brief Checks wether game is running in fullscreen mode + * \return True if fullscreen mode is enabled + */ +bool EngineBase::GetFullscreen(){ + return fullscreen; +} + +/*! \brief Toggles fullscreen mode + */ +void EngineBase::SetFullscreen(){ + SetFullscreen(!fullscreen); +} + +/*! \brief Sets fullscreen mode + * \param Fullscreen True for fullscreen mode + */ +void EngineBase::SetFullscreen(bool Fullscreen){ + SDL_Surface *screen=SDL_GetVideoSurface(); + if(screen){ + Uint32 flags = screen->flags; + if(Fullscreen && !(flags&SDL_FULLSCREEN)){ + screen=SDL_SetVideoMode(0,0,0,screen->flags^SDL_FULLSCREEN); + fullscreen=Fullscreen; + Widget::Redraw(); + } + else if(!Fullscreen && (flags&SDL_FULLSCREEN)){ + screen=SDL_SetVideoMode(0,0,0,screen->flags^SDL_FULLSCREEN); + fullscreen=Fullscreen; + Widget::Redraw(); + } + if(screen==NULL){ + // Fall back to working flags + screen = SDL_SetVideoMode(0,0,0,flags); + fullscreen=screen->flags&SDL_FULLSCREEN; + } + } +} + +/*! \brief Registers a transition to use for the next refresh + * \param Transition Transition to use + * \param Duration Length of transition in milliseconds + */ +void EngineBase::SetTransition(VN_TRANSITIONS Transition, + Uint32 Duration,SDL_Rect *Rect){ + transition_type=Transition; + transition_time=Duration; + if(Rect){ + transition_rect=*Rect; + } + else{ + EDL_SETRECT(transition_rect,0,0,width,height); + } +} + +/*! \brief Registers the default transition to use for the next refresh + */ +void EngineBase::SetTransition(SDL_Rect *Rect){ + transition_type=VT_RANDOM; + transition_time=500; + if(Rect){ + transition_rect=*Rect; + } + else{ + EDL_SETRECT(transition_rect,0,0,width,height); + } +} + +/*! \brief Drops and deletes currently running animation or effect + * \return True if an animation was dropped from the queue + */ +bool EngineBase::DestroyAnimation(){ + bool retval=false; + if(animations->GetWidgetCount()){ + // Cancel running animation + int n=animations->GetWidgetCount()-1; + Animation *aptr=(Animation*)animations->GetWidget(n); + if(aptr){ + animations->DestroyWidget(aptr); + retval=true; + } + } + return retval; +} + +/*! \brief Skips currently running animation or effect + * \return True if an animation was skipped + * + * No widgets will be freed or deleted by this call, it will only affect + * the topmost object which will remain on top until the next repaint. This + * asserts that the last frame in the animation is painted onto the screen + * before any subsequent animations. Use FlushAnimations() to drop animations + * entirely. + */ +bool EngineBase::SkipAnimation(){ + bool retval=false; + if(animations->GetWidgetCount()){ + // Cancel running animation + int n=animations->GetWidgetCount()-1; + Animation *aptr=(Animation*)animations->GetWidget(n); + if(aptr){ + aptr->Skip(); + retval=true; + } + } + return retval; +} + +/*! \brief Halt normal processing while animating a widget + * \param WidgetPtr Widget to be animated + * + * Several widgets can be queued for animation. Graphic is not persistent + * and will disappear when the animation has completed unless it has been + * drawn into the parent widget. + * + * Other widgets will not be repainted until all animation has completed. + */ +void EngineBase::AddAnimation(Animation *WidgetPtr){ + animations->AddWidget(WidgetPtr); +} + +/*! \brief Adds a widget to a specified layer + * \param WidgetPtr GUI component to add to the engine + * \param Layer Logical layer to add to (0=Top layer) + * \param Position Logical position to add to (0=Top position) + * + * The layer index will be asserted, but the position will not be padded + */ +void EngineBase::AddWidget(Widget *WidgetPtr,int Layer,int Position){ + // Assert layer + while(!widget_head->GetGroup(Layer)){ + new Group(widget_head,Layer); + } + + // Get layer and iterate to the right position + Group *wg=GetLayer(Layer); + wg->AddWidget(WidgetPtr,Position); + if(widget_head->CheckWidget(widget_focus)){ + if(WidgetPtr->GetVisible() && WidgetPtr->GetHittable()){ + widget_focus->FocusLeave(); + widget_focus=WidgetPtr; + widget_focus->FocusEnter(); + } + } +} + +/*! \brief Destroy a specified widget within a specific layer + * \param Pointer of Widget to destroy + * \param Layer Index of parent layer + */ +void EngineBase::DestroyWidget(Widget *WidgetPtr,int Layer){ + Group *wg=GetLayer(Layer); + if(wg){ + wg->DestroyWidget(WidgetPtr); + } +} + +/*! \brief Destroy a specified widget within any layer + * \param Pointer of Widget to destroy + */ +void EngineBase::DestroyWidget(Widget *WidgetPtr){ + for(int i=0;widget_head->GetGroup(i);i++){ + for(int j=0;GetWidget(i,j);j++){ + Widget *wptr=GetWidget(i,j); + if(wptr==WidgetPtr){ + Group *gptr=widget_head->GetGroup(i); + if(gptr){ + gptr->DestroyWidget(WidgetPtr); + return; + } + } + } + } +} + +/*! \brief Destroys all the widgets in a given layer + * \param Layer Layer to flush + */ +void EngineBase::DestroyLayer(int Layer){ + Group *wg=GetLayer(Layer); + if(wg){ + wg->DestroyGroup(); + } +} + +/*! \brief Shows or hides all the widgets in a given layer + * \param Layer Layer to show or hide + * \param Visible True to show widgets + */ +void EngineBase::ShowLayer(int Layer,bool Visible){ + Group *wg=GetLayer(Layer); + Widget *wb=wg->GetWidget(0); + while(wb){ + wb->SetVisible(Visible); + wb=wb->NextPtr; + } +} + +/*! \brief Limits the framerate and relieves CPU by sleeping + * \param Framerate Framerate to lock into (1s/Framerate) + */ +void EngineBase::LimitFramerate(int Framerate){ + static Uint32 lastreport=SDL_GetTicks(); + static Uint32 sleeptime=0; + static Uint32 sleeptick=0; + static Uint32 lasttick=SDL_GetTicks(); + static Uint32 framecount=0; + framecount++; + Uint32 duration=(Uint32)((double)framecount*(1000.0/(double)Framerate)); + Uint32 nowtick=SDL_GetTicks(); + Uint32 endtick=lasttick+duration; + if(Cfg::System::Verbose && nowtick>=lastreport+30000){ + // Report sleep/wake statistics + Uint32 waketime=nowtick-lastreport; + double wakepercent=(sleeptime/(double)waketime)*100; + LogVerbose("Slept %d mS of %d mS (%f%%) in %d turns (%d mS per turn)", + sleeptime,waketime,wakepercent,sleeptick,sleeptime/sleeptick); + lastreport=nowtick; + sleeptime=0; + sleeptick=0; + } + if(nowtick<=endtick){ + // Relieve CPU + SDL_Delay(endtick-nowtick); + sleeptime+=endtick-nowtick; + sleeptick++; + } + else{ + // Adjust timer without sleeping + lasttick=nowtick; + framecount=0; + } +} + +/*! \brief Relocates the mouse cursor to the given coordinates + * \param X Screen coordinate (Native resolution) + * \param Y Screen coordinate (Native resolution) + * + * Just use SDL_WarpMouse directly if you want the cursor to physical + * coordinates rather than operating at the game resolution. + */ +void EngineBase::CursorWarp(int X,int Y){ + SDL_Surface *screen=SDL_GetVideoSurface(); + if(screen){ + int x=X*(screen->w/(double)NativeWidth()); + int y=Y*(screen->h/(double)NativeHeight()); + SDL_WarpMouse(x,y); + } +} + +/*! \brief Calculates X position relative to native resolution + * \param Screen Screen surface (To get output size) + * \param X Screen coordinate + * \return X coordinate for native resolution + */ +int EngineBase::GetRelativeX(SDL_Surface *Screen,int X){ + int retval=X; + if(Screen){ + double r=NativeWidth()/(double)Screen->w; + retval=X*r; + } + return retval; +} + +/*! \brief Calculates Y position relative to native resolution + * \param Screen Screen surface (To get output size) + * \param Y Screen coordinate + * \return Y coordinate for native resolution + */ +int EngineBase::GetRelativeY(SDL_Surface *Screen,int Y){ + int retval=Y; + if(Screen){ + double r=NativeHeight()/(double)Screen->h; + retval=Y*r; + } + return retval; +} + +/*! \brief Passes ticks into the engine and regulates framerate + * + * Ticks will not be passed into the client engine if there are animations + * currently running. + * + * Must be called at each iteration loop + */ +void EngineBase::EventHostTick(){ + // Process engine ticks + if(!animations->GetWidgetCount()){ + if(!EventGameTick()){ +#if ENGINE_PROCESSTICKS + Uint32 t=SDL_GetTicks(); + while(!EventGameProcess() && t+ENGINE_PROCESSTICKS>SDL_GetTicks()); + //LogDebug("Processed: %d",SDL_GetTicks()-t); +#else + EventGameProcess(); +#endif + } + } + + // Process widget ticks + static Uint32 lasttick=SDL_GetTicks(); + Uint32 now=SDL_GetTicks(); + if(now=100){ + lasttick=now; + Group *gptr=widget_head->GetGroup(0); + while(gptr){ + Widget *wptr=gptr->GetWidget(0); + while(wptr){ + wptr->Tick(); + wptr=wptr->NextPtr; + } + gptr=gptr->NextPtr; + } + } + if(Cfg::System::Framerate){ + LimitFramerate(Cfg::System::Framerate); + } +} + +/*! \brief Paints widgets to a surface + * \param Surface Surface to paint widgets onto + * \param Toplayer An optional toplayer (To skip dialogboxes etc) + */ +void EngineBase::Paint(SDL_Surface *Surface,VN_LAYERS Toplayer){ + renderer->Render(Surface,Toplayer); + EDL_SetAlpha(Surface,0,0xFF); +} + +/*! \brief Adapts and copies the game surface to the screen display + * \param Screen The actual display surface + * \return Returns TRUE if graphics was updated + */ +bool EngineBase::EventHostPaint(SDL_Surface *Screen){ + bool retval=false; + if(Screen && Widget::PeekGlobalRefresh()){ + // Paint widgets + if(transition_type!=VT_NONE){ + // Use a transition effect + SDL_Surface *s=EDL_CreateSurface(NativeWidth(),NativeHeight()); + renderer->Render(s); + SDL_Rect r=transition_rect; + AddAnimation(new Fade(r,s,r,transition_time)); + SDL_FreeSurface(s); + + // Start animation with a recursive call + SDL_Event event; + while(SDL_PollEvent(&event)); + transition_type=VT_NONE; + retval=EventHostPaint(Screen); + } + else{ + // Copy surface to display + renderer->Update(Screen); + retval=true; + } + } + return retval; +} + +/*! \brief Get visible widget at screen coordinate + * \param X Coordinate + * \param Y Coordinate + * \return Widget at coordinate or NULL if none + */ +Widget *EngineBase::GetWidgetAt(int X,int Y){ + // Find "top" of visible widgets + Widget *wptr=0; + Group *gptr=0; + int gtop=0; + gptr=widget_head->GetGroup(gtop); + while(!wptr && gptr){ + wptr=gptr->GetWidget(X,Y); + gptr=gptr->NextPtr; + } + return wptr; +} + +/*! \brief Passes mouse click events into the engine + * \param Screen Screen surface + * \param X Screen X coordinate + * \param Y Screen Y coordinate + */ +void EngineBase::EventHostMouseLeftDown(SDL_Surface *Screen,int X,int Y){ + X=GetRelativeX(Screen,X); + Y=GetRelativeX(Screen,Y); + if(animations->GetWidgetCount()){ + // Cancel running animation + SkipAnimation(); + } + else{ + // Pass event to widgets + Widget *wptr=GetWidgetAt(X,Y); + if(!wptr || !wptr->MouseLeftDown(X,Y)){ + EventBackgroundMouseLeftDown(X,Y); + } + } +} + +/*! \brief Passes mouse click events into the engine + * \param Screen Screen surface + * \param X Screen X coordinate + * \param Y Screen Y coordinate + */ +void EngineBase::EventHostMouseLeftUp(SDL_Surface *Screen,int X,int Y){ + X=GetRelativeX(Screen,X); + Y=GetRelativeX(Screen,Y); + if(!animations->GetWidgetCount()){ + // Pass event to widgets + Widget *wptr=GetWidgetAt(X,Y); + if(!wptr || !wptr->MouseLeftUp(X,Y)){ + EventBackgroundMouseLeftUp(X,Y); + } + } +} + +/*! \brief Passes mouse click events into the engine + * \param Screen Screen surface + * \param X Screen X coordinate + * \param Y Screen Y coordinate + */ +void EngineBase::EventHostMouseRightUp(SDL_Surface *Screen,int X,int Y){ + X=GetRelativeX(Screen,X); + Y=GetRelativeX(Screen,Y); + if(!animations->GetWidgetCount()){ + // Pass event to widgets + Widget *wptr=GetWidgetAt(X,Y); + if(!wptr || !wptr->MouseRightUp(X,Y)){ + EventBackgroundMouseRightUp(X,Y); + } + } +} + +/*! \brief Passes mouse click events into the engine + * \param Screen Screen surface + * \param X Screen X coordinate + * \param Y Screen Y coordinate + */ +void EngineBase::EventHostMouseRightDown(SDL_Surface *Screen,int X,int Y){ + X=GetRelativeX(Screen,X); + Y=GetRelativeX(Screen,Y); + if(animations->GetWidgetCount()){ + // Cancel running animation + SkipAnimation(); + } + else{ + // Pass event to widgets + Widget *wptr=GetWidgetAt(X,Y); + if(!wptr || !wptr->MouseRightDown(X,Y)){ + EventBackgroundMouseRightDown(X,Y); + } + } +} + +/*! \brief Passes mouse click events into the engine + * \param Screen Screen surface + * \param X Screen X coordinate + * \param Y Screen Y coordinate + */ +void EngineBase::EventHostMouseMove(SDL_Surface *Screen,int X,int Y){ + X=GetRelativeX(Screen,X); + Y=GetRelativeX(Screen,Y); + if(!animations->GetWidgetCount()){ +#if ENGINE_HIDEMOUSE + // Force cursor + if(hidemouseCheckWidget(widget_focus)){ + widget_focus->FocusLeave(); + } + widget_focus=wptr; + if(widget_focus){ + widget_focus->FocusEnter(); + } + } + + // Pass event to widgets + if(!wptr || !wptr->MouseMove(X,Y)){ + EventBackgroundMouseMove(X,Y); + } + } +} + +/*! \brief Decodes and distributes keyboard events + * \param Key SDL Keyboard symbol struct + * + * Please note that most engine processing goes down in the KeyDown chain. + */ +void EngineBase::EventHostKeyUp(SDLKey Key){ + if(animations->GetWidgetCount()){ + } + else if(widget_head->CheckWidget(widget_focus)){ + // Pass to focused widget + if(!widget_focus->KeyUp(Key)){ + EventBackgroundKeyUp(Key); + } + } + else{ + // Register as noise + EventBackgroundKeyUp(Key); + } +} + +/*! \brief Decodes and distributes keyboard events + * \param Key SDL Keyboard symbol struct + * + * The engine only does minimal checking for system keys (Full screen, etc) + * and global hotkeys. Most of the keyboard processing goes down in the + * DialogBase class wich manages an onscreen group of widgets. + */ +void EngineBase::EventHostKeyDown(SDLKey Key){ + // Check system combinations + SDLMod mod=SDL_GetModState(); + if((mod&KMOD_LALT || mod&KMOD_RALT)){ + if(Key==SDLK_F4){ + EventGameDialog(VD_SHUTDOWN); + } + else if(KEY_RETURN(Key)){ + SetFullscreen(); + } + else if(Key==SDLK_0){ + renderer->SetScaler(GS_DEFAULT); + } + else if(Key==SDLK_1){ + renderer->SetScaler(GS_FAST); + } + else if(Key==SDLK_2){ + renderer->SetScaler(GS_NEAREST); + } + else if(Key==SDLK_3){ + renderer->SetScaler(GS_HQ2X); + } + else if(Key==SDLK_4){ + renderer->SetScaler(GS_HQ3X); + } + else if(Key==SDLK_5){ + renderer->SetScaler(GS_HQ4X); + } + + // Repaint with new scaler + for(int i=0;widget_head->GetGroup(i);i++){ + for(int j=0;GetWidget(i,j);j++){ + Widget *wptr=GetWidget(i,j); + wptr->Refresh(); + } + } + + } + else if(Key==SDLK_F5){ + EventGameDialog(VD_LOAD); + } + else if(Key==SDLK_F6){ + EventGameDialog(VD_SAVE); + } + else if(Key==SDLK_F7){ + EventGameDialog(VD_OPTIONS); + } + else if(Key==SDLK_F8){ + EventGameDialog(VD_TITLE); + } + else if(Key==SDLK_F9){ + EventGameDialog(VD_SHUTDOWN); + } + else if(Key==SDLK_F10){ + // Dump screenshot + SDL_Surface *tmp=EDL_CreateSurface(width,height); + Paint(tmp); + EDL_SaveSurface(tmp,"ViLE"); + SDL_FreeSurface(tmp); + } + else if(Key==SDLK_F11){ + Cfg::System::Verbose=!Cfg::System::Verbose; + } + else if(animations->GetWidgetCount()){ + // Cancel running animation + SkipAnimation(); + } + else{ +#if ENGINE_HIDEMOUSE + // Disable cursor when using keyboard + if(hidemouse>0){ + hidemouse--; + } + else if(hidemouse==0){ + SDL_ShowCursor(SDL_DISABLE); + hidemouse--; + } +#endif + + // Pass event to focused widget/dialog/engine + if(widget_head->CheckWidget(widget_focus) && + widget_focus->GetVisible()){ + if(KEY_REFOCUS(Key)){ + // Find next non-obscured widget + SetFocusNext(); + } + else if(!widget_focus->KeyDown(Key)){ + // Unset focus and pass event to engine + LogDebug("Engine drops keyboard focus"); + widget_focus->FocusLeave(); + widget_focus=0; + EventBackgroundKeyDown(Key); + } + } + else if(KEY_DIRECTION(Key)){ + // Find "top" visible widget capable of input + SetFocusFirst(); + } + else{ + // Pass event to engine + LogDebug("Keyboard signal passed to engine"); + EventBackgroundKeyDown(Key); + } + } +} + +/*! \brief Shifts keyboard focus from current to next widget + * \return True if a focus change occured + */ +bool EngineBase::SetFocusNext(){ + // Find next non-obscured widget + bool retval=false; + int sw=NativeWidth(); + int sh=NativeHeight(); + Widget *oldfocus=widget_focus; + if(!widget_head->CheckWidget(widget_focus)){ + // Reset to first widget + retval=SetFocusFirst(); + } + else if(widget_focus->TestMouse(0,0) && widget_focus->TestMouse(sw,sh)){ + // Reset to first widget + retval=SetFocusFirst(); + } + else{ + // Find next widget + widget_focus=0; + bool oldsearch=true; + Group *gptr=widget_head->GetGroup(0); + while(!widget_focus && gptr){ + Widget *wptr=gptr->GetWidget(0); + while(!widget_focus && wptr){ + if(wptr==oldfocus){ + oldsearch=false; + } + else if(oldsearch){ + // Wait for focused widget + } + else if(wptr->TestMouse(0,0) && wptr->TestMouse(sw,sh)){ + if(wptr->GetHittable() && wptr->GetVisible()){ + // Accept bottom widget but stop scan + oldfocus->FocusLeave(); + wptr->FocusEnter(); + wptr->KeyDown(SDLK_TAB); + widget_focus=wptr; + } + } + else{ + // Search for hittable widgets + if(wptr->GetHittable() && wptr->GetVisible()){ + // + // Mayclub krever tabbing mellom overlappende + // dialoger siden textview er fullskjerm. Vurder + // om vi mÃ¥ sette en regel mot dette. + // + //if(!wptr->TestMouse(fx1,fy1)){ + // if(!wptr->TestMouse(fx2,fy2)){ + // int tx1=wptr->GetX(); + // int ty1=wptr->GetY(); + // int tx2=tx1+wptr->GetWidth(); + // int ty2=ty1+wptr->GetHeight(); + // if(!oldfocus->TestMouse(tx1,ty1)){ + // if(!oldfocus->TestMouse(tx2,ty2)){ + oldfocus->FocusLeave(); + wptr->FocusEnter(); + wptr->KeyDown(SDLK_TAB); + widget_focus=wptr; + // } + // } + // } + //} + } + } + wptr=wptr->NextPtr; + } + gptr=gptr->NextPtr; + } + } + return retval; +} + +/*! \brief Forces keyboard focus to top widget + * \return True if a focus change occured + */ +bool EngineBase::SetFocusFirst(){ + Widget *oldfocus=widget_focus; + widget_focus=0; + Group *gptr=widget_head->GetGroup(0); + while(!widget_focus && gptr){ + Widget *wptr=gptr->GetWidget(0); + while(!widget_focus && wptr){ + if(wptr->GetHittable() && wptr->GetVisible()){ + wptr->FocusEnter(); + wptr->KeyDown(SDLK_TAB); + widget_focus=wptr; + } + wptr=wptr->NextPtr; + } + gptr=gptr->NextPtr; + } + return widget_focus && widget_focus!=oldfocus; +} + +/*! \brief Forces keyboard focus to top widget + * \return True if a focus change occured + */ +bool EngineBase::SetFocusWidget(Widget *WidgetPtr){ + if(WidgetPtr->GetHittable() && WidgetPtr->GetVisible()){ + WidgetPtr->FocusEnter(); + WidgetPtr->KeyDown(SDLK_TAB); + widget_focus=WidgetPtr; + return true; + } + else{ + return false; + } +} + + +/*! \brief Event that is called when no widgets has accepted an event + * \param X Screen coordinate + * \param Y Screen coordinate + * \return True if event was handled + */ +bool EngineBase::EventBackgroundMouseMove(int X,int Y){ + return false; +} + +/*! \brief Event that is called when no widgets has accepted an event + * \param X Screen coordinate + * \param Y Screen coordinate + * \return True if event was handled + */ +bool EngineBase::EventBackgroundMouseLeftDown(int X,int Y){ + return false; +} + +/*! \brief Event that is called when no widgets has accepted an event + * \param X Screen coordinate + * \param Y Screen coordinate + * \return True if event was handled + */ +bool EngineBase::EventBackgroundMouseRightDown(int X,int Y){ + return false; +} + +/*! \brief Event that is called when no widgets has accepted an event + * \param X Screen coordinate + * \param Y Screen coordinate + * \return True if event was handled + */ +bool EngineBase::EventBackgroundMouseLeftUp(int X,int Y){ + return false; +} + +/*! \brief Event that is called when no widgets has accepted an event + * \param X Screen coordinate + * \param Y Screen coordinate + * \return True if event was handled + */ +bool EngineBase::EventBackgroundMouseRightUp(int X,int Y){ + return false; +} + +/*! \brief Event that is called when no widgets has accepted an event + * \param Key Pressed key + * \return True if event was handled + */ +bool EngineBase::EventBackgroundKeyDown(SDLKey Key){ + return false; +} + +/*! \brief Event that is called when no widgets has accepted an event + * \param Key Pressed key + * \return True if event was handled + */ +bool EngineBase::EventBackgroundKeyUp(SDLKey Key){ + return false; +} + +/*! \brief Event which signals the need for opening a specific dialog + * \param Dialog Dialog type to open + */ +void EngineBase::EventGameDialog(VN_DIALOGS Dialog){ +} + +/*! \brief Generates an SDL event which shuts down the host application + * \return True if event was handled + */ +bool EngineBase::EventGameShutdown(){ + int c=0; + SDL_Event event; + while(SDL_PollEvent(&event)){ + c++; + } + if(c){ + LogVerbose(EDL_Format("Flushed %d system events",c)); + } + event.type=SDL_QUIT; + SDL_PushEvent(&event); + shutdown=true; + return true; +} + +/*! \brief Passes a tick event into client engine + * \return True if event was handled + * + * Tickevents are supposed to monitor stuff without regards to framerate + * or other low priority tasks which should be kept in the process event. + * + * EventGameProcess will only be called if this returned false + */ +bool EngineBase::EventGameTick(){ + return true; +} + +/*! \brief Passes a process event into client engine + * \return True if event was handled + * + * Returning false in this function will cause the engine to repeat the + * call until the designated time runs out. + */ +bool EngineBase::EventGameProcess(){ + return true; +} + +/*! \brief Defines a short string that identifies the game + * \return Game identification code + * + * The game code should not contain any whitespace or special letters + * as it will be used to generate gamespecific filenames such as + * savegames. + */ +const uString EngineBase::NativeID(){ + return "ViLE"; +} + +/*! \brief Defines a name for the game + * \return Game name + * + * Game name can contain whitespace and simular characters. + */ +const uString EngineBase::NativeName(){ + return PACKAGE_STRING; +} + +/*! \brief Returns the games native with + * \return Native width in pixels + */ +const int EngineBase::NativeWidth(){ + return width; +} + +/*! \brief Returns the games native height + * \return Native height in pixels + */ +const int EngineBase::NativeHeight(){ + return height; +} + diff --git a/engines/vileVN/engine/ebase.h b/engines/vileVN/engine/ebase.h new file mode 100644 index 0000000000..7cd9e440a0 --- /dev/null +++ b/engines/vileVN/engine/ebase.h @@ -0,0 +1,177 @@ +/*! \class EngineBase + * \brief Defines generic core API and events + * \todo Dirty rects system is disabled + * \todo Clipping is disabled + * + * EngineBase defines the core event interface for the host, any kind of mouse + * movement, keyclicking or whatever is passed into the engine through + * EngineBase which redistributes it to the dynamic widgets while keeping + * them up to date on the screen. Many events are also decoded and + * redistributed as internal events such as EventGameProcess() which tells + * the derived objects that it is time to process game scripts. + * + * EngineBase also defines logical layers (VN_LAYERS) for the games to place + * the loaded objects to make them appear logically ontop of each other + * visually on the screen. + * + * The rendering interface was moved into Renderer, a dedicated class which + * is easy to subclass for experimantal rendering techniques. + */ +#ifndef _EBASE_H_ +#define _EBASE_H_ + +// Include foundation classes +#include "../res/resources.h" +#include "../res/cache.h" +#include "renderer.h" +#include "crenderer.h" + +// Include dialog elements +#include "../dialogs/selection.h" +#include "../dialogs/textview.h" +#include "../dialogs/popimage.h" +#include "../dialogs/stdtitle.h" +#include "../dialogs/stdsave.h" +#include "../dialogs/stdload.h" +#include "../dialogs/stdmenu.h" +#include "../dialogs/options.h" +#include "../dialogs/stdhalt.h" +#include "../dialogs/stdmsg.h" +#include "../dialogs/fatal.h" + +// Configuration +#define ENGINE_PROCESSTICKS 20 //!< Milliseconds for processing +#define ENGINE_HIDEMOUSE 2 //!< Hide cursor when using keyboard + +//!< Enumerates the graphical layers +enum VN_LAYERS { //!< Enumerates viable layers + VL_OVERLAY=0, //!< Top layer + VL_DIALOG, //!< Load,save,options etc + VL_EXTRAS, //!< Overlay to ingame graphics + VL_CHOICES, //!< Command options + VL_TEXTVIEW, //!< Textview box or simular + VL_HOTSPOTS, //!< Game hotspots + VL_CHARACTERS, //!< Character graphics + VL_BACKGROUND, //!< Background graphics + VL_SIZE //!< Defines number of layers in enum +}; + +enum VN_DIALOGS { //!< Enumerates standard dialogs + VD_TITLE, //!< Title screen + VD_OPTIONS, //!< Option / Configuration screen + VD_SAVE, //!< Dialog for saving games + VD_LOAD, //!< Dialog for loading games + VD_LOG, //!< Dialog for displaying text log + VD_EXTRAS, //!< Common CG room dialog + VD_EXTRAS_CG, //!< Specialized dialog for cg + VD_EXTRAS_BGM, //!< Specialized dialog for music + VD_EXTRAS_SCENE, //!< Specialized dialog for scenes + VD_CREDITS, //!< Credit roll + VD_SHUTDOWN //!< Shutdown verification +}; + +enum VN_TRANSITIONS { //!< Enumerates screen transitions + VT_NONE=0, //!< No transition + VT_FADE, //!< Fade in new screen + VT_RANDOM, //!< Randomize a transition + VT_SIZE //!< Defines size of enum +}; + +class EngineBase { + private: + // Widget management + Group *animations; //!< Holds animation objects + Group *widget_head; //!< Holds widgets + Widget *widget_focus; //!< Pointer to focused widget + + // Engine data + int hidemouse; //!< Hides and shows mouse cursor + bool fullscreen; //!< True if fullscreen is enabled + int width; //!< Native game width + int height; //!< Native game height + bool shutdown; //!< Shutdown confirmation flag + Renderer *renderer; + + // Next transition + VN_TRANSITIONS transition_type; //!< Next screen transition + SDL_Rect transition_rect; //!< Limit transition to a rect + int transition_time; //!< Time to spend on transiton + + // Helper + void ScaledPaint(SDL_Surface *In,SDL_Surface *Out,SDL_Rect *Clip); + public: + // Contructorset + EngineBase(int Width,int Height); + virtual ~EngineBase(); + + // Redistributed events + virtual bool EventGameTick(); + virtual bool EventGameProcess(); + virtual bool EventGameShutdown(); + virtual void EventGameDialog(VN_DIALOGS Dialog); + virtual bool EventBackgroundMouseMove(int X,int Y); + virtual bool EventBackgroundMouseLeftDown(int X,int Y); + virtual bool EventBackgroundMouseRightDown(int X,int Y); + virtual bool EventBackgroundMouseLeftUp(int X,int Y); + virtual bool EventBackgroundMouseRightUp(int X,int Y); + virtual bool EventBackgroundKeyDown(SDLKey Key); + virtual bool EventBackgroundKeyUp(SDLKey Key); + + // Handlers for incoming system events + virtual void EventHostTick(); + virtual bool EventHostPaint(SDL_Surface *Screen); + virtual void EventHostMouseMove(SDL_Surface *Screen,int X,int Y); + virtual void EventHostMouseLeftDown(SDL_Surface *Screen,int X,int Y); + virtual void EventHostMouseRightDown(SDL_Surface *Screen,int X,int Y); + virtual void EventHostMouseLeftUp(SDL_Surface *Screen,int X,int Y); + virtual void EventHostMouseRightUp(SDL_Surface *Screen,int X,int Y); + virtual void EventHostKeyDown(SDLKey Key); + virtual void EventHostKeyUp(SDLKey Key); + + // Engine attributes + virtual const uString NativeID(); + virtual const uString NativeName(); + const int NativeWidth(); + const int NativeHeight(); + + // Enforces a maximum framerate by waiting the remainder + void LimitFramerate(int Framerate); + + // GUI Management + bool GetFullscreen(); + void SetFullscreen(); + void SetFullscreen(bool Fullscreen); + void SetTransition(SDL_Rect *Rect=0); + void SetTransition(VN_TRANSITIONS Transition, + Uint32 Duration,SDL_Rect *Rect=0); + void AddAnimation(Animation *WidgetPtr); + bool DestroyAnimation(); + bool SkipAnimation(); + void AddWidget(Widget *WidgetPtr,int Layer,int Position=0); + void DestroyWidget(Widget *WidgetPtr,int Layer); + void DestroyWidget(Widget *WidgetPtr); + void DestroyLayer(int Layer); + void ShowLayer(int Layer,bool Visible); + bool CheckWidget(Widget *WidgetPtr); + Group *GetLayer(int Layer); + Widget *GetWidget(int Layer,int Index); + Widget *GetWidgetAt(int X,int Y); + bool SetFocusWidget(Widget *WidgetPtr); + bool SetFocusFirst(); + bool SetFocusNext(); + bool GetShutdown(); + + // Access to internal graphics + void Paint(SDL_Surface *Surface,VN_LAYERS Toplayer=VL_OVERLAY); + + // Recalculates coordinates for the screen display + int GetRelativeX(SDL_Surface *Screen,int X); + int GetRelativeY(SDL_Surface *Screen,int Y); + + // Warps mouse cursor + void CursorWarp(int X,int Y); +}; + +#endif + + diff --git a/engines/vileVN/engine/emixer.cpp b/engines/vileVN/engine/emixer.cpp new file mode 100644 index 0000000000..5f527efeb0 --- /dev/null +++ b/engines/vileVN/engine/emixer.cpp @@ -0,0 +1,445 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "emixer.h" + +EngineMixer::EngineMixer(int Width,int Height) : EngineBase(Width,Height){ + // Set up the desired audio profile + SDL_AudioSpec desired; + desired.freq=Cfg::Audio::Frequency; + desired.samples=Cfg::Audio::Buffersize/2; + desired.size=0; + desired.callback=audio_callback; + desired.userdata=this; + desired.format=AUDIO_S16SYS; + desired.channels=Cfg::Audio::Channels; + thread_pointer=0; + thread_lock=false; + + + // Open the audio device + if(!Cfg::Audio::Enabled){ + LogVerbose("Audio is disabled"); + } + else if(SDL_OpenAudio(&desired,&hardware)<0){ + LogError("Couldn't open audio: %s",SDL_GetError()); + Cfg::Audio::Enabled=false; + } + else{ + // Give a verbose report + LogVerbose("Opened audio device:"); + LogVerbose("\tSampling frequency\t\t\t%d Hz",(int)hardware.freq); + LogVerbose("\tBuffer samples\t\t\t\t%d",(int)hardware.samples); + LogVerbose("\tBuffer size\t\t\t\t%d B",(int)hardware.size); + LogVerbose("\tAudio channels\t\t\t\t%d",(int)hardware.channels); + LogVerbose("\tAudio format\t\t\t\t0x%x",(int)hardware.format); + + // Check result + if(hardware.freq!=Cfg::Audio::Frequency){ + LogMessage("Overriding samplingrate: %d",hardware.freq); + Cfg::Audio::Frequency=hardware.freq; + } + if(hardware.size!=(unsigned int)Cfg::Audio::Buffersize){ + LogMessage("Overriding framesize: %d",hardware.size); + Cfg::Audio::Buffersize=hardware.size; + } + if(hardware.channels!=(unsigned int)Cfg::Audio::Channels){ + LogMessage("Overriding framesize: %d",hardware.channels); + Cfg::Audio::Channels=hardware.channels; + } + + // Prepare audio decoding thread + thread_lock=true; +#ifndef VILE_BUILD_SDLHG + thread_pointer=SDL_CreateThread(audio_thread,this); +#else + thread_pointer=SDL_CreateThread(audio_thread,"audio",this); +#endif + + // Start audio decoding + SDL_PauseAudio(0); + } + +#ifndef VILE_BUILD_SDLHG + // Check for CDDA CDROM + cdrom=0; + if(Cfg::Audio::CDROM>=0){ + if(SDL_CDNumDrives()>Cfg::Audio::CDROM){ + cdrom=SDL_CDOpen(Cfg::Audio::CDROM); + } + if(cdrom==0){ + LogError("Invalid CDDA source: %d",Cfg::Audio::CDROM); + } + if(cdrom){ + if(CD_INDRIVE(SDL_CDStatus(cdrom))){ + LogVerbose("Registering CDDA source: %d",Cfg::Audio::CDROM); + } + else{ + LogError("No disc in CDROM %d",Cfg::Audio::CDROM); + SDL_CDClose(cdrom); + cdrom=0; + } + } + } +#endif +} + +EngineMixer::~EngineMixer(){ +#ifndef VILE_BUILD_SDLHG + if(cdrom){ + SDL_CDClose(cdrom); + } +#endif + if(Cfg::Audio::Enabled){ + LogVerbose("Closing down audio mixer"); + if(thread_lock){ + thread_lock=false; + SDL_WaitThread(thread_pointer,NULL); + } + SDL_CloseAudio(); + StopMusic(); + StopSound(-1); + } +} + +EngineMixer::AudioChannel::AudioChannel(){ + mutex=SDL_CreateMutex(); + buffer=0; + volume=1; + enabled=true; +} + +EngineMixer::AudioChannel::~AudioChannel(){ + SDL_DestroyMutex(mutex); +} + +/*! \brief Stops current music playback + */ +void EngineMixer::StopMusic(){ + SDL_LockMutex(musicbuffer.mutex); + if(musicbuffer.buffer){ + delete musicbuffer.buffer; + musicbuffer.buffer=0; + } + SDL_UnlockMutex(musicbuffer.mutex); +} + +/*! \brief Play CDDA track + * \param Track Track to play + * \return True if track could be played back + * + * This method will play back a track using Cfg::Audio::CDROM. Negative + * values effectively disables cdda, null selects the first physical cdrom + * drive. + */ +bool EngineMixer::PlayCDDA(int Track){ + bool retval=false; +#ifndef VILE_BUILD_SDLHG + if(cdrom && CD_INDRIVE(SDL_CDStatus(cdrom))){ + LogVerbose("Playing CDDA: %d",Track); + SDL_CDPlayTracks(cdrom,Track,0,Track+1,0); + } +#endif + return retval; +} + +/*! \brief Start playing a music score + * \param Music Musical score to play back + * \return True if track wachannel->s successfully loaded + * + * Currently playing tracks are automatically faded out which will halt + * execution for some milliseconds whenever applicable. + */ +bool EngineMixer::PlayMusic(RWops *Music){ + // Try to load music resource + bool retval=false; + if(musicbuffer.enabled && Cfg::Audio::Enabled){ + StopMusic(); + if(Music && Music->Size()>8){ + // Try to identify header + char header[8]; + Music->Seek(0,SEEK_SET); + Music->Read(header,8); + AudioBuffer *buffer=0; + if(0){ + } + else if(!strncmp(header,"MThd",4) || + !strncmp(header,"MIDI",4) || + !strncmp(header,"RMID",4)){ +#ifdef VILE_FEATURE_FLUIDSYNTH + buffer=new AudioFluid(); +#else + LogMessage("Recompile with fluidsynth for MIDI support"); +#endif + } + else{ +#ifdef VILE_FEATURE_FFMPEG + // Turn to the swiss army knife .. + buffer=new AudioFFMPEG(); +#endif + } + + // Try to open the resource + Music->Seek(0,SEEK_SET); + if(buffer && buffer->Open(Music)){ + SDL_LockMutex(musicbuffer.mutex); + musicbuffer.buffer=buffer; + musicbuffer.buffer->SetReplays(-1); + musicbuffer.buffer->SetPlaying(true); + SDL_UnlockMutex(musicbuffer.mutex); + retval=true; + } + else if(buffer){ + delete buffer; + } + } + } + return retval; +} + +/*! \brief Stops given audio channel + * \param Channel Channel to stop + */ +void EngineMixer::StopSound(int Channel){ + if(Channel>=0 && Channel=0 && ChannelOpen(Sound)){ + channel->buffer=buffer; + channel->buffer->SetPlaying(true); + retval=true; + } + else{ + delete buffer; + channel->buffer=0; + } +#endif + } + SDL_UnlockMutex(soundbuffer[Channel].mutex); + } + return retval; +} + +/*! \brief Pauses background music + */ +void EngineMixer::PauseMusic(){ + SDL_LockMutex(musicbuffer.mutex); + if(musicbuffer.buffer){ + musicbuffer.buffer->SetPlaying(false); + } + SDL_UnlockMutex(musicbuffer.mutex); +} + +/*! \brief Resumes background music + */ +void EngineMixer::ResumeMusic(){ + SDL_LockMutex(musicbuffer.mutex); + if(musicbuffer.enabled && musicbuffer.buffer){ + musicbuffer.buffer->SetPlaying(true); + } + SDL_UnlockMutex(musicbuffer.mutex); +} + +/*! \brief Enables or disables background music + * \param Enabled True to enable + */ +void EngineMixer::SetMusicEnabled(bool Enabled){ + SDL_LockMutex(musicbuffer.mutex); + musicbuffer.enabled=Enabled; + SDL_UnlockMutex(musicbuffer.mutex); +} + +/*! \brief Wether background music is enabled + * \return True if music is enabled + * + * Background music will not load or decode at all unless it is enabled. All + * other bgm controls will be ignored if the music mixer is disabled. + */ +bool EngineMixer::GetMusicEnabled(){ + SDL_LockMutex(musicbuffer.mutex); + bool retval=musicbuffer.enabled; + SDL_UnlockMutex(musicbuffer.mutex); + return retval; +} + +/*! \brief Enable or disable a given audio channel + * \param Channel Audio channel to set + * \param Enabled True to enable channel + * + * A disabled channel will refuse to load any audio resources, all other + * audio controls will ignore that channel as long as it is disabled. + */ +void EngineMixer::SetSoundEnabled(int Channel,bool Enabled){ + if(Channel>=0 && Channel=0 && Channel=0 && Channel=0 && Channelthread_lock); + LogVerbose("Audio decoding thread is ready"); + while(e->thread_lock){ + // Process music + bool relax=true; + SDL_LockMutex(e->musicbuffer.mutex); + if(e->musicbuffer.enabled && e->musicbuffer.buffer){ + relax&=e->musicbuffer.buffer->Decode(); + } + SDL_UnlockMutex(e->musicbuffer.mutex); + + // Process sound data + for(int i=0;isoundbuffer[i].mutex); + if(e->soundbuffer[i].enabled && e->soundbuffer[i].buffer){ + relax&=e->soundbuffer[i].buffer->Decode(); + } + SDL_UnlockMutex(e->soundbuffer[i].mutex); + } + + // Relieve cpu + if(relax){ + SDL_Delay(10); + } + } + return 0; +} + +/*! \brief Decodes and buffers audio data (Called internally from SDL) + * \param udata Engine object + * \param stream Buffer to fill with raw 16bit pcm + * \param len Length of stream + */ +void EngineMixer::audio_callback(void *udata,Uint8 *stream,int len){ + // Mix music data + memset(stream,0,len); + EngineMixer *e=(EngineMixer*)udata; + SDL_LockMutex(e->musicbuffer.mutex); + if(e->musicbuffer.enabled && e->musicbuffer.buffer){ + e->musicbuffer.buffer->Mix(stream,len,e->musicbuffer.volume); + } + SDL_UnlockMutex(e->musicbuffer.mutex); + + // Mix sounds and voices + for(int i=0;isoundbuffer[i].mutex); + if(e->soundbuffer[i].enabled && e->soundbuffer[i].buffer){ + e->soundbuffer[i].buffer->Mix(stream,len,e->soundbuffer[i].volume); + } + SDL_UnlockMutex(e->soundbuffer[i].mutex); + } +} + + diff --git a/engines/vileVN/engine/emixer.h b/engines/vileVN/engine/emixer.h new file mode 100644 index 0000000000..51236eca63 --- /dev/null +++ b/engines/vileVN/engine/emixer.h @@ -0,0 +1,78 @@ +/*! \class EngineMixer + * \brief Embeds audio playback and decoding to the engine object + * + * This class encapsulates SDL_mixer functionality and facilitates music, + * voice and sfx clips to be played. You can use as many channels as you + * want to, but only one clip per channel at a time. + * + * This class is basically a driver class for the decoder implementations + * in the media/ folder (See Audio class). We currently support FFMPEG and + * Fluidsynth which should serve most purposes on desktop computers atleast. + */ + +#ifndef _EMIXER_H_ +#define _EMIXER_H_ + +#include "ebase.h" +#include "../media/audio.h" + +#define AUDIO_CHANNELS 32 + +#ifdef VILE_FEATURE_FFMPEG +#include "../media/affmpeg.h" +#endif +#ifdef VILE_FEATURE_FLUIDSYNTH +#include "../media/afluid.h" +#endif + +class EngineMixer : public EngineBase +{ + private: + // Audio hardware interface + static void audio_callback(void *udata,Uint8 *stream,int len); + static int audio_thread(void *arg); + SDL_Thread *thread_pointer; + bool thread_lock; + + // Declare Audio Channels + struct AudioChannel { + AudioChannel(); + ~AudioChannel(); + AudioBuffer *buffer; + SDL_mutex *mutex; + bool enabled; + double volume; + }musicbuffer,soundbuffer[AUDIO_CHANNELS]; + + // Internal handling + SDL_AudioSpec hardware; +#ifndef VILE_BUILD_SDLHG + SDL_CD *cdrom; +#endif + public: + EngineMixer(int Width,int Height); + ~EngineMixer(); + + // Mixer API + bool PlayCDDA(int Track); + bool PlayMusic(RWops *Music); + void PauseMusic(); + void ResumeMusic(); + void StopMusic(); + bool SetVolumeMusic(int Volume); + int GetVolumeMusic(); + bool PlaySound(RWops *Sound,int Channel,int Replays=0); + void StopSound(int Channel=-1); + bool SetVolumeSound(int Channel,int Volume); + int GetVolumeSound(int Channel); + + // Disable or enable audio (ie. muting) + void SetMusicEnabled(bool Enabled); + bool GetMusicEnabled(); + void SetSoundEnabled(int Channel,bool Enabled); + bool GetSoundEnabled(int Channel); +}; + +#endif + + diff --git a/engines/vileVN/engine/evideo.cpp b/engines/vileVN/engine/evideo.cpp new file mode 100644 index 0000000000..ca9526eca1 --- /dev/null +++ b/engines/vileVN/engine/evideo.cpp @@ -0,0 +1,260 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "evideo.h" + +EngineVideo::EngineVideo(int Width,int Height) : EngineMixer(Width,Height){ + asurface=0; + aframe=0; + videobuffer=0; + thread_pointer=0; + thread_lock=false; + videomutex=SDL_CreateMutex(); + if(Cfg::Video::Overlay){ + //! \todo Find out why buffering video overlays causes memory corruption + Cfg::Video::Framecount=1; + } + if(Cfg::Video::Enabled){ + thread_lock=true; +#ifdef VILE_BUILD_SDLHG + thread_pointer=SDL_CreateThread(video_thread,"video",this); +#else + thread_pointer=SDL_CreateThread(video_thread,this); +#endif + } + else{ + LogVerbose("Video is disabled"); + } +} + +EngineVideo::~EngineVideo(){ + if(Cfg::Video::Enabled){ + LogVerbose("Closing down video player"); + StopVideo(); + if(thread_lock){ + thread_lock=false; + SDL_WaitThread(thread_pointer,NULL); + } + } + SDL_DestroyMutex(videomutex); +} + +/*! \brief Background thread to decode and buffer video data + */ +int EngineVideo::video_thread(void *arg){ + EngineVideo *e=(EngineVideo*)arg; + while(!e->thread_lock); + LogVerbose("Video decoding thread is ready"); + bool decode; + while(e->thread_lock){ + // Process music + decode=false; + SDL_LockMutex(e->videomutex); + if(e->videobuffer){ + decode=e->videobuffer->Decode(); + } + SDL_UnlockMutex(e->videomutex); + + // Relieve cpu + if(!decode){ + SDL_Delay(10); + } + } + return 0; +} + +/*! \brief Event signaling start of video playback + */ +void EngineVideo::EventGameStartVideo(){ +} + +/*! \brief Event signaling end of video playback + */ +void EngineVideo::EventGameStopVideo(){ +} + +/*! \brief Stops video playback and frees all related objects + */ +void EngineVideo::StopVideo(){ + SDL_LockMutex(videomutex); + if(asurface || videobuffer){ + EventGameStopVideo(); + } + if(asurface){ + for(int i=0;asurface[i];i++){ + SDL_FreeSurface(asurface[i]); + } + delete asurface; + asurface=0; + aframe=0; + } + if(videobuffer){ + StopSound(0); + delete videobuffer; + videobuffer=0; + } + SDL_UnlockMutex(videomutex); +} + +/*! \brief Plays an animation sequence + * \param Animation Nullterminated sequence to animate + * \return True if animation was accepted + */ +bool EngineVideo::PlayAnimation(SDL_Surface **Animation){ + StopVideo(); + if(Animation && Cfg::Video::Enabled){ + asurface=Animation; + aframe=0; + EventGameStartVideo(); + } + return Animation; +} + +/*! \brief Playback a video resource + * \param Video Video resource to decode and play + * \return True if Video was accepted + */ +bool EngineVideo::PlayVideo(RWops *Video){ + bool retval=false; + if(Video && Cfg::Video::Enabled){ + StopVideo(); + SDL_LockMutex(videomutex); +#ifdef VILE_FEATURE_FFMPEG + videobuffer=new VideoFFMPEG(); +#endif + if(videobuffer && videobuffer->Open(Video)){ + StopSound(-1); + StopMusic(); + videofps=videobuffer->Framerate(); + LogVerbose("Opened video stream at %f fps",videofps); + PlaySound(Video,0,0); + retval=true; + } + else{ + delete videobuffer; + videobuffer=0; + } + SDL_UnlockMutex(videomutex); + } + return retval; +} + +/*! \brief Overrides paint event to display video + * \param Screen Display surface + * \return True if display was updates + * + * This method will only act when video is loaded, otherwise calls will + * be passed down to the base implementation. + */ +bool EngineVideo::EventHostPaint(SDL_Surface *Screen){ + bool retval=false; + if(videobuffer){ + // Blit video frames until we run out + SDL_LockMutex(videomutex); + bool running=videobuffer->Paint(); + SDL_UnlockMutex(videomutex); + if(running){ + LimitFramerate(videofps); + } + else{ + StopVideo(); + } + } + else if(asurface){ + // Blit animation sequence until user cancels + if(asurface[aframe]){ + SDL_BlitSurface(asurface[aframe++],0,Screen,0); + retval=true; + } + else{ + aframe=0; + } + + // Fixed framerate limit for animations + LimitFramerate(10); + } + else{ + // Call base painter + retval=EngineBase::EventHostPaint(Screen); + } + return retval; +} + +/*! \brief Checks wether any video or animations are currently playing + * \return True if any video resources are playing + */ +bool EngineVideo::PlayingVideo(){ + return (asurface || videobuffer); +} + +void EngineVideo::EventHostTick(){ + if(!PlayingVideo()){ + EngineBase::EventHostTick(); + } +} + +void EngineVideo::EventHostMouseMove(SDL_Surface *Screen,int X,int Y){ + if(!PlayingVideo()){ + EngineBase::EventHostMouseMove(Screen,X,Y); + } +} + +void EngineVideo::EventHostMouseLeftDown(SDL_Surface *Screen,int X,int Y){ + if(!PlayingVideo()){ + EngineBase::EventHostMouseLeftDown(Screen,X,Y); + } +} + +void EngineVideo::EventHostMouseRightDown(SDL_Surface *Screen,int X,int Y){ + if(!PlayingVideo()){ + EngineBase::EventHostMouseRightDown(Screen,X,Y); + } +} + +void EngineVideo::EventHostMouseLeftUp(SDL_Surface *Screen,int X,int Y){ + if(PlayingVideo()){ + StopVideo(); + } + else{ + EngineBase::EventHostMouseLeftUp(Screen,X,Y); + } +} + +void EngineVideo::EventHostMouseRightUp(SDL_Surface *Screen,int X,int Y){ + if(PlayingVideo()){ + StopVideo(); + } + else{ + EngineBase::EventHostMouseRightUp(Screen,X,Y); + } +} + +void EngineVideo::EventHostKeyDown(SDLKey Key){ + if(PlayingVideo()){ + if(KEY_ACTION(Key)){ + StopVideo(); + } + } + else{ + EngineBase::EventHostKeyDown(Key); + } +} + +void EngineVideo::EventHostKeyUp(SDLKey Key){ + if(!PlayingVideo()){ + EngineBase::EventHostKeyUp(Key); + } +} + diff --git a/engines/vileVN/engine/evideo.h b/engines/vileVN/engine/evideo.h new file mode 100644 index 0000000000..4ac7b446f0 --- /dev/null +++ b/engines/vileVN/engine/evideo.h @@ -0,0 +1,71 @@ +/*! \class EngineVideo + * \brief Implements video and animation features + * + * This class is basically a driver class for the decoder implementations + * in the media/ folder (See Video class). We currently only support FFMPEG. + * + * Video is considered a special case of media that requires as little + * overhead as possible. To accomplish this it overrides the host events + * of the base, effectively blocking all other execution until the video + * has ended. Input events (Mouse/keyboard) are used to exit the video state + * prematurely, and the paint event are used to paint the frames. + * + * Animation in this context means series of bitmaps that animate into a + * video-like sequence. Please check EngineBase for dynamical widgets that + * animate on their own accord. + * + * The EngineMixer class is called to handle any audio streams. + */ + +#ifndef _EVIDEO_H_ +#define _EVIDEO_H_ + +#include "emixer.h" +#include "../media/video.h" + +#ifdef VILE_FEATURE_FFMPEG +#include "../media/vffmpeg.h" +#endif + +class EngineVideo : public EngineMixer{ + private: + // Video + static int video_thread(void *arg); //!< Video decoding thread + SDL_Thread *thread_pointer; //!< Pointer to thread + bool thread_lock; //!< Locks thread + VideoBuffer *videobuffer; //!< Decoded and buffered video + SDL_mutex *videomutex; //!< Mutex to lock video stream + double videofps; //!< Frames per second + + // Simple animation + SDL_Surface **asurface; //!< Animation frames in memory + int aframe; //!< Current animation frame + protected: + // Video events + virtual void EventGameStartVideo(); + virtual void EventGameStopVideo(); + public: + EngineVideo(int Width,int Height); + ~EngineVideo(); + + // Video API + void StopVideo(); + bool PlayingVideo(); + virtual bool PlayAnimation(SDL_Surface **Animation); + virtual bool PlayVideo(RWops *Video); + + // Override host events + void EventHostTick(); + bool EventHostPaint(SDL_Surface *Screen); + void EventHostMouseMove(SDL_Surface *Screen,int X,int Y); + void EventHostMouseLeftDown(SDL_Surface *Screen,int X,int Y); + void EventHostMouseRightDown(SDL_Surface *Screen,int X,int Y); + void EventHostMouseLeftUp(SDL_Surface *Screen,int X,int Y); + void EventHostMouseRightUp(SDL_Surface *Screen,int X,int Y); + void EventHostKeyDown(SDLKey Key); + void EventHostKeyUp(SDLKey Key); +}; + +#endif + + diff --git a/engines/vileVN/engine/evn.cpp b/engines/vileVN/engine/evn.cpp new file mode 100644 index 0000000000..83367e2c7d --- /dev/null +++ b/engines/vileVN/engine/evn.cpp @@ -0,0 +1,736 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "evn.h" + +EngineVN::EngineVN(int Width,int Height) : EngineVideo(Width,Height){ + // Set default values + msgdelay_interval=25; + msgdelay_enabled=true; + keyok=false; + keycancel=false; + skip=false; + savename="Unknown"; + + // Enable default audio channels + SetMusicEnabled(true); + SetSoundEnabled(VA_SOUNDS,true); + SetSoundEnabled(VA_VOICES,true); + + // Load sequencer and create logo + Sequences=new Sequencer(this); + Sequences->LogoRandom(); + + // Assign a standard menu + if(Cfg::System::Mainmenu){ + AddWidget(new StdMenu(this),VL_DIALOG); + } + + // Apply standard patches + uString path=Cfg::Path::game; + if(Cfg::Path::game.length()){ + r_voices.AddResource(new ArchiveViLE(path+"/patch_voices.pck")); + r_videos.AddResource(new ArchiveViLE(path+"/patch_videos.pck")); + r_scripts.AddResource(new ArchiveViLE(path+"/patch_scripts.pck")); + r_other.AddResource(new ArchiveViLE(path+"/patch_other.pck")); + r_images.AddResource(new ArchiveViLE(path+"/patch_images.pck")); + r_bgm.AddResource(new ArchiveViLE(path+"/patch_bgm.pck")); + r_se.AddResource(new ArchiveViLE(path+"/patch_se.pck")); + } + r_voices.AddResource(new ArchiveViLE("patch_voices.pck")); + r_videos.AddResource(new ArchiveViLE("patch_videos.pck")); + r_scripts.AddResource(new ArchiveViLE("patch_scripts.pck")); + r_other.AddResource(new ArchiveViLE("patch_other.pck")); + r_images.AddResource(new ArchiveViLE("patch_images.pck")); + r_bgm.AddResource(new ArchiveViLE("patch_bgm.pck")); + r_se.AddResource(new ArchiveViLE("patch_se.pck")); +} + +EngineVN::~EngineVN(){ + delete Sequences; +} + +/*! \brief Checks existence of resource file and logs verbosely + * \param Path Directory + * \param Resource Filename path relative to Path + * \return True if file exists + */ +bool EngineVN::ProbeResource(uString Path,uString Resource){ + uString path=EDL_Realname(Path+Resource); + bool retval=EDL_ReadableFile(path); + LogVerbose("\t%-40s%s",path.c_str(),retval?"PASS":"FAIL"); + return retval; +} + +/*! \brief Checks if two strings matches and logs verbosely + * \param S1 String + * \param S2 String to compare with + * \return True if the strings matches (case insensitive) + */ +bool EngineVN::ProbeString(uString S1,uString S2){ + S1=EDL_Lower(S1); + S2=EDL_Lower(S2); + bool retval=(S1==S2); + uString msg=S1+uString(" == ")+S2; + LogVerbose("\t%-40s%s",msg.c_str(),retval?"PASS":"FAIL"); + return retval; +} + +/*! \brief Gets current state of control key + * \returns True if keyboard initiated skip is enabled + */ +bool EngineVN::keyctrl(){ +#ifdef VILE_BUILD_SDLHG + Uint8 *keystate=SDL_GetKeyboardState(NULL); +#else + Uint8 *keystate=SDL_GetKeyState(NULL); +#endif + return keystate[SDLK_RCTRL] || keystate[SDLK_LCTRL]; +} + +/*! \brief Enumerates a list of voice archives + * \param Pointer to list to populate + * \return Number of items added to list + */ +int EngineVN::GetVoices(Stringlist *List){ + return r_voices.EnumerateArchives(List); +} + +/*! \brief Enumerates a list of archives containing scripts + * \param Pointer to list to populate + * \return Number of items added to list + */ +int EngineVN::GetScripts(Stringlist *List){ + return r_scripts.EnumerateArchives(List); +} + +/*! \brief Enumerates a list of archives with undefined resources + * \param Pointer to list to populate + * \return Number of items added to list + */ +int EngineVN::GetOther(Stringlist *List){ + return r_other.EnumerateArchives(List); +} + +/*! \brief Enumerates a list of image archives + * \param Pointer to list to populate + * \return Number of items added to list + */ +int EngineVN::GetImages(Stringlist *List){ + return r_images.EnumerateArchives(List); +} + +/*! \brief Enumerates a list of music archives + * \param Pointer to list to populate + * \return Number of items added to list + */ +int EngineVN::GetBGM(Stringlist *List){ + return r_bgm.EnumerateArchives(List); +} + +/*! \brief Enumerates a list of sound effect archives + * \param Pointer to list to populate + * \return Number of items added to list + */ +int EngineVN::GetSE(Stringlist *List){ + return r_se.EnumerateArchives(List); +} + +/*! \brief Enumerates a list of video archives + * \param Pointer to list to populate + * \return Number of items added to list + */ +int EngineVN::GetVideo(Stringlist *List){ + return r_videos.EnumerateArchives(List); +} + +/*! \brief Add archive of voice resources + * \param Name Path to archive(s) + */ +void EngineVN::AddVoices(ArchiveBase *Archive){ + r_voices.AddResource(Archive); +} + +/*! \brief Add archive of video resources + * \param Name Path to archive(s) + */ +void EngineVN::AddVideo(ArchiveBase *Archive){ + r_videos.AddResource(Archive); +} + +/*! \brief Add archive of game script resources + * \param Name Path to archive(s) + */ +void EngineVN::AddScripts(ArchiveBase *Archive){ + r_scripts.AddResource(Archive); +} + +/*! \brief Add archive of undefined resources + * \param Name Path to archive(s) + */ +void EngineVN::AddOther(ArchiveBase *Archive){ + r_other.AddResource(Archive); +} + +/*! \brief Add archive of image resources + * \param Name Path to archive(s) + */ +void EngineVN::AddImages(ArchiveBase *Archive){ + r_images.AddResource(Archive); +} + +/*! \brief Add archive of music resources + * \param Name Path to archive(s) + */ +void EngineVN::AddBGM(ArchiveBase *Archive){ + r_bgm.AddResource(Archive); +} + +/*! \brief Add archive of sound effect resources + * \param Name Path to archive(s) + */ +void EngineVN::AddSE(ArchiveBase *Archive){ + r_se.AddResource(Archive); +} + +/*! \brief Add video resource to animation queue + * \param Name Name of video resource + * \return True if resource was accepted + */ +bool EngineVN::QueueVideo(uString Name){ + RWops *ops=LoadVideo(Name); + if(ops){ + AddAnimation(new VideoWidget(this,ops)); + } + return ops; +} + +/*! \brief Add video resource to animation queue + * \param Video Blob containing video resource + * \return True if resource was accepted + */ +bool EngineVN::QueueVideo(RWops *Video){ + if(Video){ + AddAnimation(new VideoWidget(this,Video)); + } + return Video; +} + +/*! \brief Add music resource to animation queue + * \param Name Name of video resource + * \return True if resource was accepted + * + * Music track will start playing when previously queued Animation objects + * have completed. It will not affect graphics in any way (unless you set + * the widget graphic). + */ +bool EngineVN::QueueMusic(uString Name){ + RWops *ops=LoadMusic(Name); + if(ops){ + AddAnimation(new MusicWidget(this,ops)); + } + return ops; +} + +/*! \brief Add music resource to animation queue + * \param Music Blob containing music resource + * \return True if resource was accepted + * + * Music track will start playing when previously queued Animation objects + * have completed. It will not affect graphics in any way (unless you set + * the widget graphic). + */ +bool EngineVN::QueueMusic(RWops *Music){ + if(Music){ + AddAnimation(new MusicWidget(this,Music)); + } + return Music; +} + +/*! \brief Play video resource + * \param Name Name of video resource + * \return True if resource was accepted + */ +bool EngineVN::PlayVideo(uString Name){ + // Try to load video resource + RWops *ops=r_videos.GetResource(Name); + bool retval=false; + if(ops){ + LogVerbose("Playing video: %s",Name.c_str()); + retval=EngineVideo::PlayVideo(ops); + delete ops; + } + else{ + LogVerbose("Invalid video resource: %s",Name.c_str()); + } + return retval; +} + +/*! \brief Play video resource + * \param Video Blob containing video resource + * \return True if resource was accepted + */ +bool EngineVN::PlayVideo(RWops *Video){ + return EngineVideo::PlayVideo(Video); +} + +/*! \brief Play music resource by name + * \param Name Name of music resource + * \return True if resource was accepted + */ +bool EngineVN::PlayMusic(uString Name){ + // Try to load music resource (NULL stops current) + RWops *ops=r_bgm.GetResource(Name); + bool retval=false; + if(ops){ + LogVerbose("Playing music: %s",Name.c_str()); + retval=EngineMixer::PlayMusic(ops); + delete ops; + } + return retval; +} + +/*! \brief Play a preloaded music resource + * \param Music Blob containing music resource + * \return True if resource was accepted + */ +bool EngineVN::PlayMusic(RWops *Music){ + return EngineMixer::PlayMusic(Music); +} + +/*! \brief Plays music track + * \param Track Numeric to discern bgm id + * \return True if the track was identified and started + * + * Older games are often designed to play music from the original CDROM, + * but has been altered to play said track from a mp3/ogg file using the + * track index to format a standard name. + * + * This method will poll the standard sources and play the first audio + * source to match a identification. + */ +bool EngineVN::PlayTrack(int Track){ + bool retval=PlayCDDA(Track); + if(!retval) retval=PlayMusic(EDL_Format("%02d",Track)); + if(!retval) retval=PlayMusic(EDL_Format("%d",Track)); + if(!retval) retval=PlayMusic(EDL_Format("TK%02d",Track)); + if(!retval) retval=PlayMusic(EDL_Format("TK%d",Track)); + if(!retval) retval=PlayMusic(EDL_Format("TK_%02d",Track)); + if(!retval) retval=PlayMusic(EDL_Format("TK_%d",Track)); + if(!retval) retval=PlayMusic(EDL_Format("TK-%02d",Track)); + if(!retval) retval=PlayMusic(EDL_Format("TK-%d",Track)); + return retval; +} + +/*! \brief Play sound effect + * \param Name Name of sound resource + * \param Channel Audio channel to play sample in + * \param Repear Times to repeat track (0=Play once) + * \return True if resource was accepted + */ +bool EngineVN::PlaySound(uString Name,int Channel,int Repeat){ + // Try to load sound resource (NULL stops current) + RWops *ops=r_se.GetResource(Name); + bool retval=false; + if(ops){ + LogVerbose("Playing sound: %s@%d",Name.c_str(),Channel); + retval=EngineMixer::PlaySound(ops,Channel,Repeat); + delete ops; + } + else{ + LogVerbose("Invalid sound resource: %s",Name.c_str()); + delete ops; + } + return retval; +} + +/*! \brief Play voice resource + * \param Voice Audio data + * \param Channel Audio channel to play sample in + * \return True if resource was accepted + */ +bool EngineVN::PlaySound(RWops *SE,int Channel,int Repeat){ + // Try to load voice resource (NULL stops current) + return EngineMixer::PlaySound(SE,Channel,Repeat); +} + +/*! \brief Play voice resource + * \param Name Name of sound resource + * \param Channel Audio channel to play sample in + * \return True if resource was accepted + */ +bool EngineVN::PlayVoice(uString Name,int Channel){ + // Try to load voice resource (NULL stops current) + RWops *ops=r_voices.GetResource(Name); + bool retval=false; + if(ops){ + LogVerbose("Playing voice: %s@%d",Name.c_str(),Channel); + retval=EngineMixer::PlaySound(ops,Channel); + delete ops; + } + else{ + LogVerbose("Invalid sound resource: %s",Name.c_str()); + delete ops; + } + return retval; +} + +/*! \brief Play voice resource + * \param Voice Audio data + * \param Channel Audio channel to play sample in + * \return True if resource was accepted + */ +bool EngineVN::PlayVoice(RWops *Voice,int Channel){ + // Try to load voice resource (NULL stops current) + return EngineMixer::PlaySound(Voice,Channel); +} + +/*! \brief Loads script resource + * \param Name Name of resource to load + * \param Ext Extension (In case of name-crashes across types) + * \return Pointer to resource that must be freed + */ +RWops *EngineVN::LoadScript(uString Name,uString Ext){ + return r_scripts.GetResource(EDL_DefaultExtension(Name,Ext)); +} + +/*! \brief Loads undefined resource + * \param Name Name of resource to load + * \param Ext Extension (In case of name-crashes across types) + * \return Pointer to resource that must be freed + */ +RWops *EngineVN::LoadOther(uString Name,uString Ext){ + return r_other.GetResource(EDL_DefaultExtension(Name,Ext)); +} + +/*! \brief Loads video resource + * \param Name Name of resource to load + * \param Ext Extension (In case of name-crashes across types) + * \return Pointer to resource that must be freed + */ +RWops *EngineVN::LoadVideo(uString Name,uString Ext){ + return r_videos.GetResource(EDL_DefaultExtension(Name,Ext)); +} + +/*! \brief Loads music resource + * \param Name Name of resource to load + * \param Ext Extension (In case of name-crashes across types) + * \return Pointer to resource that must be freed + */ +RWops *EngineVN::LoadMusic(uString Name,uString Ext){ + return r_bgm.GetResource(EDL_DefaultExtension(Name,Ext)); +} + +/*! \brief Loads sound resource + * \param Name Name of resource to load + * \param Ext Extension (In case of name-crashes across types) + * \return Pointer to resource that must be freed + */ +RWops *EngineVN::LoadSE(uString Name,uString Ext){ + return r_se.GetResource(EDL_DefaultExtension(Name,Ext)); +} + +/*! \brief Loads voice resources + * \param Name Name of resource to load + * \param Ext Extension (In case of name-crashes across types) + * \return Pointer to resource that must be freed + */ +RWops *EngineVN::LoadVoice(uString Name,uString Ext){ + return r_voices.GetResource(EDL_DefaultExtension(Name,Ext)); +} + +/*! \brief Loads image resource + * \param Name Name of resource to load + * \param Ext Extension (In case of name-crashes across types) + * \return Pointer to resource that must be freed + */ +SDL_Surface *EngineVN::LoadImage(uString Name,uString Ext){ + return r_images.GetImage(EDL_DefaultExtension(Name,Ext)); +} + +/*! \brief Loads animation resource + * \param Name Name of resource to load + * \return Pointer to resource that must be freed + */ +SDL_Surface **EngineVN::LoadAnimation(uString Name,uString Ext){ + return r_images.GetAnimation(EDL_DefaultExtension(Name,Ext)); +} + +/*! \brief Registers a textual name to use for savegames + * \param Name New savegame name + */ +void EngineVN::SetSavename(uString Name){ + savename=Name; +} + +/*! \brief Reads name to use for savegames + * \returns Savegame name + */ +uString EngineVN::GetSavename(){ + return savename; +} + +void EngineVN::SetSkipmode(bool Skip){ + skip=Skip; +} + +bool EngineVN::GetSkipmode(){ + return skip; +} + +void EngineVN::SetMessageDelayEnabled(bool Enabled){ + msgdelay_enabled=Enabled; +} + +void EngineVN::SetMessageDelayInterval(int Interval){ + msgdelay_interval=Interval; +} + +bool EngineVN::GetMessageDelayEnabled(){ + return msgdelay_enabled; +} + +int EngineVN::GetMessageDelayInterval(){ + return msgdelay_interval; +} + +void EngineVN::EventGameDialog(VN_DIALOGS Dialog){ + if(Dialog==VD_OPTIONS){ + AddWidget(new Options(this),VL_DIALOG); + } + else if(Dialog==VD_SHUTDOWN){ + AddWidget(new StdHalt(this),VL_DIALOG); + } + else if(Dialog==VD_SAVE){ + AddWidget(new StdSave(this),VL_DIALOG); + } + else if(Dialog==VD_LOAD){ + AddWidget(new StdLoad(this),VL_DIALOG); + } +} + +bool EngineVN::EventSaveSystem(){ + // Save system settings + Savegame save(NativeID(),999); + save.SaveUint32("skipmode",skip); + save.SaveString("savename",savename); + save.SaveUint32("fullscreen",GetFullscreen()); + save.SaveUint32("msgspeed_enabled",msgdelay_enabled); + save.SaveUint32("msgspeed_delay",msgdelay_interval); + save.SaveUint32("bgm_enabled",GetMusicEnabled()); + save.SaveUint32("bgm_volume",GetVolumeMusic()); + save.SaveUint32("voice_enabled",GetSoundEnabled(VA_VOICES)); + save.SaveUint32("voice_volume",GetVolumeSound(VA_VOICES)); + save.SaveUint32("se_enabled",GetSoundEnabled(VA_SOUNDS)); + save.SaveUint32("se_volume",GetVolumeSound(VA_SOUNDS)); + + // Store unlocked resources + Uint8 *buffer; + Uint32 length; + if(cgflags.GetBuffer(&buffer,&length)){ + save.SaveBuffer("cgflags",buffer,length); + } + if(sceneflags.GetBuffer(&buffer,&length)){ + save.SaveBuffer("hflags",buffer,length); + } + return save.Write(); +} + +bool EngineVN::EventLoadSystem(){ + Savegame load(NativeID(),999); + if(load.Read()){ + // Load settings + Uint32 tmp; + load.LoadUint32("skipmode",&tmp); + skip=tmp; + load.LoadUint32("fullscreen",&tmp); + SetFullscreen(tmp); + load.LoadUint32("msgspeed_enabled",&tmp); + SetMessageDelayEnabled(tmp); + load.LoadUint32("msgspeed_delay",&tmp); + SetMessageDelayInterval(tmp); + load.LoadUint32("bgm_enabled",&tmp); + SetMusicEnabled(tmp); + load.LoadUint32("bgm_volume",&tmp); + SetVolumeMusic(tmp); + load.LoadUint32("voice_enabled",&tmp); + SetSoundEnabled(VA_VOICES,tmp); + load.LoadUint32("voice_volume",&tmp); + SetVolumeSound(VA_VOICES,tmp); + load.LoadUint32("se_enabled",&tmp); + SetSoundEnabled(VA_SOUNDS,tmp); + load.LoadUint32("se_volume",&tmp); + SetVolumeSound(VA_SOUNDS,tmp); + load.LoadString("savename",&savename); + + // Load previously unlocked features + Uint8 *buffer; + Uint32 length; + if(load.LoadBuffer("cgflags",&buffer,&length)){ + cgflags.SetBuffer(buffer,length); + delete [] buffer; + } + if(load.LoadBuffer("hflags",&buffer,&length)){ + sceneflags.SetBuffer(buffer,length); + delete [] buffer; + } + + return true; + } + else{ + return false; + } +} + +void EngineVN::EventNew(){ +} + +bool EngineVN::EventSave(int Index){ + return false; +} + +bool EngineVN::EventLoad(int Index){ + return false; +} + +void EngineVN::EventSelect(int Selection){ +} + +bool EngineVN::EventBackgroundMouseLeftDown(int X,int Y){ + if(skip){ + SetSkipmode(false); + } + keyok=true; + return true; +} + +bool EngineVN::EventBackgroundMouseRightDown(int X,int Y){ + if(skip){ + SetSkipmode(false); + } + keycancel=true; + return true; +} + +bool EngineVN::EventBackgroundKeyDown(SDLKey Key){ + if(skip){ + SetSkipmode(false); + } + switch(Key){ + case SDLK_RETURN: + case SDLK_KP_ENTER: + case SDLK_SPACE: keyok=true; break; + case SDLK_ESCAPE: keycancel=true; break; + case SDLK_RCTRL: + case SDLK_LCTRL: break; + case SDLK_LEFT: + case SDLK_UP: + case SDLK_DOWN: + case SDLK_RIGHT: break; + default: break; + } + return true; +} + +bool EngineVN::EventBackgroundKeyUp(SDLKey Key){ + switch(Key){ + case SDLK_RETURN: + case SDLK_KP_ENTER: + case SDLK_SPACE: break; + case SDLK_ESCAPE: break; + case SDLK_RCTRL: + case SDLK_LCTRL: break; + case SDLK_LEFT: + case SDLK_UP: + case SDLK_DOWN: + case SDLK_RIGHT: break; + default: break; + } + return true; +} + +/*! \brief Registers a lockable resource name for an index + * \param Index Index of resource name + * \param Name Name of the resource + */ +void EngineVN::RegisterCG(int Index,uString Name){ + cgmap.SetString(Index,Name); +} + +/*! \brief Registers a lockable resource name for an index + * \param Index Index of resource name + * \param Name Name of the resource + */ +void EngineVN::RegisterScene(int Index,uString Name){ + scenemap.SetString(Index,Name); +} + +/*! \brief Reads data from a mapped image resource + * \param Index Index to get data from + * \param Flag True if resource has been unlocked (/seen) + * \param Name Name of the resource + * \return True if data was found for Index + * + * This method can be used to construct CG-Room features. The resources + * should be unlocked by calling UnlockCG() when loading event cgs. + */ +bool EngineVN::MapCG(int Index,bool *Flag,uString *Name){ + bool retval=Index=0){ + cgflags.SetBit(index,true); + } +} + +/*! \brief Unlocks a CG (So it can be seen in a cg-room feature) + * \param Name Name of the resource to unlock + */ +void EngineVN::UnlockScene(uString Name){ + int index=scenemap.GetString(EDL_Searchname(Name)); + if(index>=0){ + sceneflags.SetBit(index,true); + } +} + diff --git a/engines/vileVN/engine/evn.h b/engines/vileVN/engine/evn.h new file mode 100644 index 0000000000..a2742f2b67 --- /dev/null +++ b/engines/vileVN/engine/evn.h @@ -0,0 +1,149 @@ +/*! \class EngineVN + * \brief Encapsulates the base classes into a VN-friendly API + * + * EngineVN forms a common high level API for specialized Game engines to + * derive from. It helps manage and using game resources as well as providing + * standard VN functionality such as skip mode to derived engines. + */ +#ifndef _EVN_H_ +#define _EVN_H_ + +// Include base classes +#include "evideo.h" +#include "sequencer.h" + +// Include resource widgets +#include "../widgets/mwidget.h" +#include "../widgets/vwidget.h" + + +enum VN_AUDIOCHANNEL { //!< Default audio channel enumeration + VA_ALL=-1, //!< All audio channels (Not music) + VA_SYSTEM=0, //!< Default channel for system sounds + VA_SOUNDS, //!< Default channel for game effects + VA_VOICES //!< Default channel for voices +}; + +class EngineVN : public EngineVideo { + private: + // Game resources + Resources r_se; //!< Sound Effect resources + Resources r_bgm; //!< Background music resources + Resources r_scripts; //!< Script resources + Resources r_videos; //!< Video resources + Resources r_images; //!< Image resources + Resources r_voices; //!< Voice resources + Resources r_other; //!< Other resources + + // Variable data + uString savename; //!< Current savegame name + bool skip; //!< Skipmode state + Stringlist cgmap; //!< Maps cg resources for cgroom + Stringlist scenemap; //!< Maps story resources for memory + DVector cgflags; //!< Flags seen graphics + DVector sceneflags; //!< Flags read stories + + // Message delay + bool msgdelay_enabled; //!< Message delay activation + int msgdelay_interval; //!< Message delay value + protected: + // Track input + bool keyok; //!< ok (return etc) is registered + bool keycancel; //!< cancel (esc etc) is registered + bool keyctrl(); //!< skip key is registered + + // Checks for presence of resource files + static bool ProbeResource(uString Path,uString Resource); + static bool ProbeString(uString S1,uString S2); + public: + // Constructor to keep parameters + EngineVN(int Width,int Height); + ~EngineVN(); + + // Resource handler + int GetVoices(Stringlist *List); + int GetScripts(Stringlist *List); + int GetOther(Stringlist *List); + int GetImages(Stringlist *List); + int GetBGM(Stringlist *List); + int GetSE(Stringlist *List); + int GetVideo(Stringlist *List); + void AddVoices(ArchiveBase *Archive); + void AddScripts(ArchiveBase *Archive); + void AddOther(ArchiveBase *Archive); + void AddImages(ArchiveBase *Archive); + void AddBGM(ArchiveBase *Archive); + void AddSE(ArchiveBase *Archive); + void AddVideo(ArchiveBase *Archive); + void AddPatches(ArchiveBase *Archive); + RWops *LoadScript(uString Name,uString Ext=""); + RWops *LoadOther(uString Name,uString Ext=""); + RWops *LoadMusic(uString Name,uString Ext=""); + RWops *LoadVoice(uString Name,uString Ext=""); + RWops *LoadSE(uString Name,uString Ext=""); + RWops *LoadVideo(uString Name,uString Ext=""); + SDL_Surface *LoadImage(uString Name,uString Ext=""); + SDL_Surface **LoadAnimation(uString N,uString E=""); + + // Media handling + virtual bool PlayVideo(uString Name); + virtual bool PlayVideo(RWops *Video); + virtual bool QueueVideo(uString Name); + virtual bool QueueVideo(RWops *Video); + virtual bool PlayMusic(uString Name); + virtual bool PlayMusic(RWops *Music); + virtual bool PlayTrack(int Track); + virtual bool QueueMusic(uString Name); + virtual bool QueueMusic(RWops *Music); + virtual bool PlayVoice(uString Name,int Channel=VA_VOICES); + virtual bool PlayVoice(RWops *Voice,int Channel=VA_VOICES); + virtual bool PlaySound(uString Name, + int Channel=VA_SOUNDS,int Repeat=0); + virtual bool PlaySound(RWops *Voice, + int Channel=VA_SOUNDS,int Repeat=0); + + // Variable data + void SetSavename(uString Name); + uString GetSavename(); + + // Skipmode + virtual void SetSkipmode(bool Skip); + virtual bool GetSkipmode(); + + // Maps seen/unseen resources + void RegisterCG(int Index,uString Name); + void RegisterScene(int Index,uString Name); + bool MapCG(int Index,bool *Flag,uString *Name); + bool MapScene(int Index,bool *Flag,uString *Name); + void UnlockCG(uString Name); + void UnlockScene(uString Name); + + // Non-persistent animation sequences + Sequencer *Sequences; + + // Message delay + virtual void SetMessageDelayEnabled(bool Enabled); + virtual void SetMessageDelayInterval(int Interval); + virtual bool GetMessageDelayEnabled(); + virtual int GetMessageDelayInterval(); + + // Define Standard dialog events + virtual void EventGameDialog(VN_DIALOGS Dialog); + + // Loading and saving + virtual bool EventSaveSystem(); + virtual bool EventLoadSystem(); + virtual bool EventSave(int Index); + virtual bool EventLoad(int Index); + virtual void EventNew(); + virtual void EventSelect(int Selection); + + // Pick up background events + virtual bool EventBackgroundMouseLeftDown(int X,int Y); + virtual bool EventBackgroundMouseRightDown(int X,int Y); + virtual bool EventBackgroundKeyDown(SDLKey Key); + virtual bool EventBackgroundKeyUp(SDLKey Key); +}; + +#endif + diff --git a/engines/vileVN/engine/renderer.cpp b/engines/vileVN/engine/renderer.cpp new file mode 100644 index 0000000000..8ce4974442 --- /dev/null +++ b/engines/vileVN/engine/renderer.cpp @@ -0,0 +1,161 @@ +#include "renderer.h" + +Renderer::Renderer(Group *Widgets,Group *Animations,int Width,int Height){ + scaler=GS_DEFAULT; + width=Width; + height=Height; + widgets=Widgets; + animations=Animations; + gamesurface=SDL_CreateRGBSurface(SDL_SWSURFACE,Width,Height,32,0,0,0,0); +} + +Renderer::~Renderer(){ + SDL_FreeSurface(gamesurface); +} + +/*! \brief Select scaling method + * \param Scaler Scaling method + */ +void Renderer::SetScaler(GRAPHIC_SCALER Scaler){ + scaler=Scaler; +} + +/*! \brief Scales one surface onto another + * \param In Surface to scale + * \param Out Output surface + */ +void Renderer::Scale(SDL_Surface *In,SDL_Surface *Out){ + if(scaler==GS_DEFAULT && In->w==Out->w && In->h==Out->h){ + // Optimize for unresized blits + EDL_BlitSurface(In,0,Out,0); + } + else if(scaler==GS_DEFAULT){ + // Default to software blits + EDL_ResizeSurface(In,Out,true); + } +#ifdef VILE_FEATURE_SCALER + else if(scaler==GS_FAST){ + EDL_ResizeSurface(In,Out,false); + } + else if(scaler==GS_NEAREST){ + EDL_ResizeSurface(In,Out,true); + } + else if(scaler==GS_HQ2X){ + EDL_ScaleHQ2X(In,Out); + } + else if(scaler==GS_HQ3X){ + EDL_ScaleHQ3X(In,Out); + } + else if(scaler==GS_HQ4X){ + EDL_ScaleHQ4X(In,Out); + } +#endif + else{ + EDL_ResizeSurface(In,Out,true); + LogError("Unknown scaler: %d",scaler); + } +} + +/*! \brief Renders graphics from scratch + * \param Surface Surface to render to + * \param Top Top layer to render + * + * This method is a versatile interface that allows drawing any part of the + * widgets at any time. It is typically uncached and designed to be used for + * dumping screenshots for savegames etc. + */ +void Renderer::Render(SDL_Surface *Surface,int Top){ + // Unset global refresh and check if we need scaling + SDL_Rect clip={0,0,width,height}; + Widget::GetGlobalRefresh(&clip); + EDL_LIMIT(clip.w,0,width); + EDL_LIMIT(clip.h,0,height); + + // Paint widgets to the surface + int l=widgets->GetGroupCount()-1; + Group *gptr=widgets->GetGroup(l); + while(gptr){ + // Paint widgets + Widget *wptr=gptr->GetWidget(gptr->GetWidgetCount()-1); + while(wptr){ + if(wptr->GetVisible()){ + wptr->Copy(gamesurface); + } + wptr=wptr->PrevPtr; + } + + // Check for top layer + if((--l)<(int)Top){ + break; + } + gptr=gptr->PrevPtr; + } + + // Scale output + if(Surface->w!=width || Surface->h!=height){ + Scale(gamesurface,Surface); + } + else{ + EDL_BlitSurface(gamesurface,&clip,Surface,&clip); + } +} + +/*! \brief Updates graphics + * \param Surface Surface to render to + * \param Top Top layer to render + * + * This method is the primary rendering interface for the ViLE core. It is + * meant to perform any caching transparantly and only paint unobstructed, + * visible widgets to save time and processing power. The rendered output + * can be either an animation or the currently visible widgets. + * + * Some implementations might expect the Surface to be preloaded with + * graphics from the previous run (eg. dirty rects) so use Render() if + * you just want a simple screendump. + */ +void Renderer::Update(SDL_Surface *Surface){ + if(animations->GetWidgetCount()){ + UpdateAnimations(Surface); + } + else{ + UpdateWidgets(Surface); + } +} + +/*! \brief Updates animation rendering + * \param Surface Surface to render to + */ +void Renderer::UpdateAnimations(SDL_Surface *Surface){ + // Animate current graphics directly to screen + int n=animations->GetWidgetCount()-1; + Animation *aptr=(Animation*)animations->GetWidget(n); + if(aptr){ + // Get animation frame + SDL_Surface *tmpsurface=EDL_CreateSurface(width,height); + EDL_BlitSurface(gamesurface,0,tmpsurface,0); + aptr->Copy(tmpsurface); + Scale(tmpsurface,Surface); + + // Update base graphics and drop widget + if(!aptr->Continue()){ + EDL_BlitSurface(tmpsurface,0,gamesurface,0); + animations->DestroyWidget(aptr); + } + SDL_FreeSurface(tmpsurface); + } +} + +/*! \brief Updates widget graphics + * \param Surface Surface to render to + * + * The default widget rendering is the traditional method of rendering all + * widgets (Idendical to the Render() method) which is very safe, but also + * very inefficient. + */ +void Renderer::UpdateWidgets(SDL_Surface *Surface){ + // Reset global refresh while checking it + if(Widget::PeekGlobalRefresh()){ + Render(Surface,0); + } +} + diff --git a/engines/vileVN/engine/renderer.h b/engines/vileVN/engine/renderer.h new file mode 100644 index 0000000000..0229950ecd --- /dev/null +++ b/engines/vileVN/engine/renderer.h @@ -0,0 +1,50 @@ +/*! \class Renderer + * \brief Renders widgets onto a surface + * + * Rendering was originally a part of EngineBase but was diverted to make + * it easier to implement and test alternative versions in the live code + * base. The base class is a port of the original rendering method. + */ + +#ifndef _RENDERER_H_ +#define _RENDERER_H_ + +#include "../widgets/widget.h" +#include "../widgets/animation.h" +#include "../widgets/group.h" + +enum GRAPHIC_SCALER { //!< Enumerates scalers + GS_DEFAULT=0, //!< Disable scaling + GS_FAST, //!< Resize with quick and dirty scaler + GS_NEAREST, //!< Resize using nearest neigbour + GS_HQ2X, //!< HQ2X High quality scaler + GS_HQ3X, //!< HQ3X High quality scaler + GS_HQ4X, //!< HQ4X High quality scaler + GS_SIZE //!< Defines size of enum +}; + +class Renderer { + protected: + // Object data + GRAPHIC_SCALER scaler; + SDL_Surface *gamesurface; + Group *animations; + Group *widgets; + int height; + int width; + + // Internal rendering interface + virtual void Scale(SDL_Surface *In,SDL_Surface *Out); + virtual void UpdateAnimations(SDL_Surface *Surface); + virtual void UpdateWidgets(SDL_Surface *Surface); + public: + // Public rendering interface + Renderer(Group *Widgets,Group *Animations,int Width,int Height); + virtual ~Renderer(); + virtual void Render(SDL_Surface *Surface,int Top=0); + virtual void Update(SDL_Surface *Surface); + virtual void SetScaler(GRAPHIC_SCALER Scaler); +}; + +#endif + diff --git a/engines/vileVN/engine/sequencer.cpp b/engines/vileVN/engine/sequencer.cpp new file mode 100644 index 0000000000..a040abbafd --- /dev/null +++ b/engines/vileVN/engine/sequencer.cpp @@ -0,0 +1,295 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "sequencer.h" +#include "evn.h" + +Sequencer::Sequencer(EngineVN *Engine){ + engine=Engine; +} + +/*! \brief Blends a text logo onto a surface + * \param Surface Surface to blend into + * \param FG Color for text + */ +void Sequencer::CreateLogoText(SDL_Surface *Surface,SDL_Color FG){ + // Create a logo + Printer printer; + printer.Resize(Surface->w,Surface->h); + + // Get proper fontsize + int size=36; + int width=0,height=0; + int lastwidth=0,lastheight=0; + for(int i=4;i<400;i++){ + printer.SetFontSize(i); + if(printer.GetTextSize("ViLE",&width,&height)){ + if(width>Surface->w || height>Surface->h){ + break; + } + else if(width>lastwidth || height>lastheight){ + size=i; + } + } + } + printer.SetFontSize(size); + + // Print name + printer.Clear(); + printer.SetFontColor(FG.r,FG.g,FG.b); + printer.Move(0,0); + printer.Print("V LE",0); + printer.Copy(Surface); + + // Calculate and print 'i' in different color + if(printer.GetTextSize("V",&width,&height)){ + printer.SetFontColor(0xFF,0,0); + printer.Move(width,0); + printer.Clear(); + printer.Print("i",0); + printer.Copy(Surface); + } +} + +/*! \brief Creates a transparent logo + * \param Width Width of logo surface + * \param Height Height of logo surface + * \param FG Color for text + * \return Alpha blendable text logo + */ +SDL_Surface *Sequencer::CreateLogoAlpha(int Width,int Height,SDL_Color FG){ + SDL_Surface *surface=EDL_CreateSurface(Width,Height); + CreateLogoText(surface,FG); + return surface; +} + +/*! \brief Creates an opaque logo + * \param Width Width of logo surface + * \param Height Height of logo surface + * \param BG Color for background + * \param FG Color for text + * \return Alpha blendable text logo + */ +SDL_Surface *Sequencer::CreateLogoOpaque(int Width,int Height, + SDL_Color BG,SDL_Color FG){ + SDL_Surface *surface=EDL_CreateSurface(Width,Height); + boxRGBA(surface,0,0,Width,Height,BG.r,BG.g,BG.b,0xFF); + CreateLogoText(surface,FG); + return surface; +} + +void Sequencer::RollPaddedVertical(SDL_Surface *Surface){ + // Pad surface + Uint8 r,g,b,a; + int height=engine->NativeHeight(); + SDL_Surface *tmp=EDL_CreateSurface(Surface->w,Surface->h+(height*2)); + EDL_GetPixel(Surface,Surface->w/2,0,&r,&g,&b,&a); + boxRGBA(tmp,0,0,Surface->w,height,r,g,b,0xFF); + EDL_GetPixel(Surface,Surface->w/2,Surface->h-1,&r,&g,&b,&a); + boxRGBA(tmp,0,height+Surface->h,Surface->w, + (height*2)+Surface->h,r,g,b,0xFF); + SDL_Rect rpad={0,height,Surface->w,Surface->h}; + EDL_BlitSurface(Surface,0,tmp,&rpad); + + // Roll padded surface + RollVertical(tmp); + SDL_FreeSurface(tmp); +} + +void Sequencer::RollVertical(SDL_Surface *Surface){ + // Fade to background color + Uint8 r,g,b,a; + int width=engine->NativeWidth(); + int height=engine->NativeHeight(); + SDL_Rect full={0,0,width,height}; + EDL_GetPixel(Surface,Surface->w/2,0,&r,&g,&b,&a); + engine->AddAnimation(new FadeColor(full,r,g,b,1000)); + + // Scroll staffroll + SDL_Rect start={0,0,Surface->w,Surface->h}; + SDL_Rect end={0,Surface->h-height,Surface->w,Surface->h}; + SDL_Rect dst={(width-Surface->w)/2,0,Surface->w,height}; + Uint32 time=SEQUENCER_MSPERSCREEN*(Surface->h/(double)height); + engine->AddAnimation(new Scroll(dst,Surface,start,end,time)); +} + +/*! \brief Picks a random ViLE logo with a random background color + */ +void Sequencer::LogoRandom(){ + if(EDL_Random()){ + LogoRandom(0xFF,0xFF,0xFF); + } + else{ + LogoRandom(0x00,0x00,0x00); + } +} + +/*! \brief Picks a random ViLE logo + * \param R Color value for background + * \param G Color value for background + * \param B Color value for background + */ +void Sequencer::LogoRandom(Uint8 R,Uint8 G,Uint8 B){ + int seed=EDL_Random(0,1); + if(seed==0){ + LogoZoom(R,G,B); + } + else{ + LogoFlicker(R,G,B); + } +} + +/*! \brief Zoom into a ViLE logo and fade in url + * \param R Color value for background + * \param G Color value for background + * \param B Color value for background + */ +void Sequencer::LogoZoom(Uint8 R,Uint8 G,Uint8 B){ + // Get sizes and colors + SDL_Color BG={R,G,B}; + SDL_Color FG={0xFF,0xFF,0xFF}; + if((R+G+B)/3>0xFF/2){ + EDL_SETCOLOR(FG,0x00,0x00,0x00); + } + int ratio=8; + int width=engine->NativeWidth(); + int height=engine->NativeHeight(); + int widthlogo=0,heightlogo=0; + Printer printer; + printer.SetFontSize(12); + printer.GetTextSize("ViLE",&widthlogo,&heightlogo); + SDL_Rect rfull={0,0,width,height}; + SDL_Rect rend={(width-(width/ratio))/2, + (height-(height/ratio))/2, + width/ratio,height/ratio}; + + // Create surfaces + int widthurl=0,heighturl=0; + printer.GetTextSize("www.vilevn.org",&widthurl,&heighturl); + printer.Resize(widthurl,heighturl); + SDL_Rect rsmall={0,0,widthurl,heighturl}; + SDL_Rect rurl={rend.x+((rend.w-widthurl)/2), + height*(heightlogo/(double)widthlogo), + widthurl,heighturl}; + SDL_Surface *urlnormal=EDL_CreateSurface(rurl.w,rurl.h); + boxRGBA(urlnormal,0,0,rurl.w,rurl.h,BG.r,BG.g,BG.b,0xFF); + SDL_Surface *urlred=EDL_CopySurface(urlnormal,0); + SDL_Surface *logobig=CreateLogoOpaque(width,height,BG,FG); + + // Print tag + printer.Clear(); + printer.SetFontColor(0xFF,0x00,0x00); + printer.Print("www.vilevn.org",0); + printer.Copy(urlred); + printer.SetFontColor(FG.r,FG.g,FG.b); + printer.Reprint(0); + printer.Copy(urlnormal); + + // Assert background and zoom in logo + engine->AddAnimation(new FadeColor(rfull,R,G,B,150)); + engine->AddAnimation(new Zoom(logobig,rfull,rfull,rend,400)); + + // Animate url + engine->AddAnimation(new Fade(rurl,urlnormal,rsmall,1000)); + engine->AddAnimation(new Fade(rurl,urlred,rsmall,1000)); + engine->AddAnimation(new Fade(rurl,urlred,rsmall,2000)); + SDL_FreeSurface(urlnormal); + SDL_FreeSurface(urlred); + SDL_FreeSurface(logobig); +} + +/*! \brief Loads a simple "powered by" logo + * \param R Color value for background + * \param G Color value for background + * \param B Color value for background + */ +void Sequencer::LogoFlicker(Uint8 R,Uint8 G,Uint8 B){ + // Get size and color + SDL_Color BG={R,G,B}; + SDL_Color FG={0xFF,0xFF,0xFF}; + if((R+G+B)/3>0xFF/2){ + EDL_SETCOLOR(FG,0x00,0x00,0x00); + } + int width=engine->NativeWidth(); + int height=engine->NativeHeight(); + SDL_Rect rfull={0,0,width,height}; + SDL_Rect rlogo={0,0,80,55}; + SDL_Rect rend={(width-rlogo.w)/2,(height-rlogo.h)/2,rlogo.w,rlogo.h}; + + // Create surfaces + int widthtag=0,heighttag=0; + Printer printer; + printer.SetFontSize(12); + printer.GetTextSize("Powered By",&widthtag,&heighttag); + printer.Resize(widthtag,heighttag); + SDL_Rect rsmall={0,0,widthtag,heighttag}; + SDL_Rect rtag={rend.x+((rend.w-widthtag)/2), + rend.y-heighttag,widthtag,heighttag}; + SDL_Surface *tagback=EDL_CreateSurface(rtag.w,rtag.h); + boxRGBA(tagback,0,0,rtag.w,rtag.h,BG.r,BG.g,BG.b,0xFF); + SDL_Surface *tagnormal=EDL_CopySurface(tagback,0); + SDL_Surface *tagdim=EDL_CopySurface(tagback,0); + SDL_Surface *logofg=CreateLogoOpaque(rlogo.w,rlogo.h,BG,FG); + SDL_Surface *logodim=EDL_CopySurface(logofg,0); + SDL_Surface *logodark=EDL_CopySurface(logofg,0); + SDL_Surface *logoblend=EDL_CreateSurface(rlogo.w,rlogo.h); + boxRGBA(logoblend,0,0,rlogo.w,rlogo.h,BG.r,BG.g,BG.b,0xFF); + SDL_SetAlpha(logoblend,SDL_SRCALPHA,128); + EDL_BlitSurface(logoblend,0,logodim,0); + EDL_BlitSurface(logoblend,0,logodark,0); + EDL_BlitSurface(logoblend,0,logodark,0); + + // Print slogan + printer.Clear(); + printer.SetFontColor((FG.r+BG.r)/2,(FG.g+BG.g)/2,(FG.b+BG.b)/2); + printer.Print("Powered By",0); + printer.Copy(tagdim); + printer.SetFontColor(FG.r,FG.g,FG.b); + printer.Reprint(0); + printer.Copy(tagnormal); + + // Assert background + engine->AddAnimation(new FadeColor(rfull,R,G,B,100)); + + // Flicker + engine->AddAnimation(new Fade(rtag,tagdim,rsmall,20)); + engine->AddAnimation(new Fade(rend,logodark,rlogo,50)); + engine->AddAnimation(new Fade(rtag,tagdim,rsmall,200)); + engine->AddAnimation(new Fade(rtag,tagback,rsmall,10)); + engine->AddAnimation(new Fade(rtag,tagdim,rsmall,10)); + engine->AddAnimation(new Fade(rtag,tagback,rsmall,10)); + + // Dim + engine->AddAnimation(new Fade(rtag,tagnormal,rsmall,30)); + engine->AddAnimation(new Fade(rend,logodim,rlogo,100)); + engine->AddAnimation(new Fade(rtag,tagback,rsmall,20)); + engine->AddAnimation(new Fade(rtag,tagback,rsmall,40)); + + // Really light + engine->AddAnimation(new Fade(rtag,tagnormal,rsmall,30)); + engine->AddAnimation(new Fade(rend,logofg,rlogo,100)); + engine->AddAnimation(new Fade(rend,logofg,rlogo,3000)); + + // Free surfaces + SDL_FreeSurface(logofg); + SDL_FreeSurface(logodim); + SDL_FreeSurface(logodark); + SDL_FreeSurface(logoblend); + SDL_FreeSurface(tagnormal); + SDL_FreeSurface(tagdim); + SDL_FreeSurface(tagback); +} + + diff --git a/engines/vileVN/engine/sequencer.h b/engines/vileVN/engine/sequencer.h new file mode 100644 index 0000000000..18e229982b --- /dev/null +++ b/engines/vileVN/engine/sequencer.h @@ -0,0 +1,40 @@ +/*! \class Sequencer + * \brief Encapsulates series of animations as sequences + * + * Sequencer is a pure convenience class and does not introduce any features + * on its own. It is a helper-class for EngineVN that encapsulates series of + * animations into sequences that can be loaded by executing a function. + */ +#ifndef _SEQUENCER_H_ +#define _SEQUENCER_H_ + +#define SEQUENCER_MSPERSCREEN 10000 + +#include "../dialogs/dlgbase.h" + +class EngineVN; + +class Sequencer { + private: + EngineVN *engine; + protected: + // Macros for creating logo source + void CreateLogoText(SDL_Surface *Surface,SDL_Color FG); + SDL_Surface *CreateLogoAlpha(int Width,int Height,SDL_Color FG); + SDL_Surface *CreateLogoOpaque(int Width,int Height, + SDL_Color FG,SDL_Color BG); + public: + // Constructor registers host engine + Sequencer(EngineVN *Engine); + + // Available sequences + void RollVertical(SDL_Surface *Surface); + void RollPaddedVertical(SDL_Surface *Surface); + void LogoRandom(); + void LogoRandom(Uint8 R,Uint8 G,Uint8 B); + void LogoZoom(Uint8 R,Uint8 G,Uint8 B); + void LogoFlicker(Uint8 R,Uint8 G,Uint8 B); +}; + +#endif + diff --git a/engines/vileVN/external/SDL/gfx/SDL_framerate.c b/engines/vileVN/external/SDL/gfx/SDL_framerate.c new file mode 100644 index 0000000000..d95255bafc --- /dev/null +++ b/engines/vileVN/external/SDL/gfx/SDL_framerate.c @@ -0,0 +1,135 @@ +/* + +SDL_framerate: framerate manager + +LGPL (c) A. Schiffler + +*/ + +#include "SDL_framerate.h" + +/*! +\brief Initialize the framerate manager. + +Initialize the framerate manager, set default framerate of 30Hz and +reset delay interpolation. + +\param manager Pointer to the framerate manager. +*/ +void SDL_initFramerate(FPSmanager * manager) +{ + /* + * Store some sane values + */ + manager->framecount = 0; + manager->rate = FPS_DEFAULT; + manager->rateticks = (1000.0f / (float) FPS_DEFAULT); + manager->lastticks = SDL_GetTicks(); +} + +/*! +\brief Set the framerate in Hz + +Sets a new framerate for the manager and reset delay interpolation. +Rate values must be between FPS_LOWER_LIMIT and FPS_UPPER_LIMIT inclusive to be accepted. + +\param manager Pointer to the framerate manager. +\param rate The new framerate in Hz (frames per second). + +\return 0 for sucess and -1 for error. +*/ +int SDL_setFramerate(FPSmanager * manager, int rate) +{ + if ((rate >= FPS_LOWER_LIMIT) && (rate <= FPS_UPPER_LIMIT)) { + manager->framecount = 0; + manager->rate = rate; + manager->rateticks = (1000.0f / (float) rate); + return (0); + } else { + return (-1); + } +} + +/*! +\brief Return the current target framerate in Hz + +Get the currently set framerate of the manager. + +\param manager Pointer to the framerate manager. + +\return Current framerate in Hz or -1 for error. +*/ +int SDL_getFramerate(FPSmanager * manager) +{ + if (manager == NULL) { + return (-1); + } else { + return (manager->rate); + } +} + +/*! +\brief Return the current framecount. + +Get the current framecount from the framerate manager. +A frame is counted each time SDL_framerateDelay is called. + +\param manager Pointer to the framerate manager. + +\return Current frame count or -1 for error. +*/ +int SDL_getFramecount(FPSmanager * manager) +{ + if (manager == NULL) { + return (-1); + } else { + return ((Uint32)manager->framecount); + } +} + +/*! +\brief Delay execution to maintain a constant framerate and calculate fps. + +Generate a delay to accomodate currently set framerate. Call once in the +graphics/rendering loop. If the computer cannot keep up with the rate (i.e. +drawing too slow), the delay is zero and the delay interpolation is reset. + +\param manager Pointer to the framerate manager. +*/ +void SDL_framerateDelay(FPSmanager * manager) +{ + Uint32 current_ticks; + Uint32 target_ticks; + Uint32 the_delay; + + /* + * No manager, no delay + */ + if (manager == NULL) + return; + + /* + * Initialize uninitialized manager + */ + if (manager->lastticks == 0) + SDL_initFramerate(manager); + + /* + * Next frame + */ + manager->framecount++; + + /* + * Get/calc ticks + */ + current_ticks = SDL_GetTicks(); + target_ticks = manager->lastticks + (Uint32) ((float) manager->framecount * manager->rateticks); + + if (current_ticks <= target_ticks) { + the_delay = target_ticks - current_ticks; + SDL_Delay(the_delay); + } else { + manager->framecount = 0; + manager->lastticks = SDL_GetTicks(); + } +} diff --git a/engines/vileVN/external/SDL/gfx/SDL_framerate.h b/engines/vileVN/external/SDL/gfx/SDL_framerate.h new file mode 100644 index 0000000000..9e91bb10a1 --- /dev/null +++ b/engines/vileVN/external/SDL/gfx/SDL_framerate.h @@ -0,0 +1,79 @@ + +/* + +SDL_framerate: framerate manager + +LGPL (c) A. Schiffler + +*/ + +#ifndef _SDL_framerate_h +#define _SDL_framerate_h + +/* Set up for C function definitions, even when using C++ */ +#ifdef __cplusplus +extern "C" { +#endif + + /* --- */ + +#include "SDL.h" + + /* --------- Definitions */ + +/*! +\brief Highest possible rate supported by framerate controller in Hz (1/s). +*/ +#define FPS_UPPER_LIMIT 200 + +/*! +\brief Lowest possible rate supported by framerate controller in Hz (1/s). +*/ +#define FPS_LOWER_LIMIT 1 + +/*! +\brief Default rate of framerate controller in Hz (1/s). +*/ +#define FPS_DEFAULT 30 + +/*! +\brief Structure holding the state and timing information of the framerate controller. +*/ + typedef struct { + Uint32 framecount; + float rateticks; + Uint32 lastticks; + Uint32 rate; + } FPSmanager; + + /* ---- Function Prototypes */ + +#if defined(WIN32) || defined(WIN64) +# if defined(DLL_EXPORT) && !defined(LIBSDL_GFX_DLL_IMPORT) +# define SDL_FRAMERATE_SCOPE __declspec(dllexport) +# else +# ifdef LIBSDL_GFX_DLL_IMPORT +# define SDL_FRAMERATE_SCOPE __declspec(dllimport) +# endif +# endif +#endif +#ifndef SDL_FRAMERATE_SCOPE +# define SDL_FRAMERATE_SCOPE extern +#endif + + /* Functions return 0 or value for sucess and -1 for error */ + + SDL_FRAMERATE_SCOPE void SDL_initFramerate(FPSmanager * manager); + SDL_FRAMERATE_SCOPE int SDL_setFramerate(FPSmanager * manager, int rate); + SDL_FRAMERATE_SCOPE int SDL_getFramerate(FPSmanager * manager); + SDL_FRAMERATE_SCOPE int SDL_getFramecount(FPSmanager * manager); + SDL_FRAMERATE_SCOPE void SDL_framerateDelay(FPSmanager * manager); + + /* --- */ + + /* Ends C function definitions when using C++ */ +#ifdef __cplusplus +} +#endif + +#endif /* _SDL_framerate_h */ diff --git a/engines/vileVN/external/SDL/gfx/SDL_gfxBlitFunc.c b/engines/vileVN/external/SDL/gfx/SDL_gfxBlitFunc.c new file mode 100644 index 0000000000..e976da39c0 --- /dev/null +++ b/engines/vileVN/external/SDL/gfx/SDL_gfxBlitFunc.c @@ -0,0 +1,576 @@ +/* + +SDL_gfxBlitFunc: custom blitters (part of SDL_gfx library) + +LGPL (c) A. Schiffler + +*/ + +#include "SDL_gfxBlitFunc.h" + +/*! +\brief Alpha adjustment table for custom blitter. + +The table provides values for a modified, non-linear +transfer function which maintain brightness. + +*/ +static unsigned int GFX_ALPHA_ADJUST_ARRAY[256] = { + 0, /* 0 */ + 15, /* 1 */ + 22, /* 2 */ + 27, /* 3 */ + 31, /* 4 */ + 35, /* 5 */ + 39, /* 6 */ + 42, /* 7 */ + 45, /* 8 */ + 47, /* 9 */ + 50, /* 10 */ + 52, /* 11 */ + 55, /* 12 */ + 57, /* 13 */ + 59, /* 14 */ + 61, /* 15 */ + 63, /* 16 */ + 65, /* 17 */ + 67, /* 18 */ + 69, /* 19 */ + 71, /* 20 */ + 73, /* 21 */ + 74, /* 22 */ + 76, /* 23 */ + 78, /* 24 */ + 79, /* 25 */ + 81, /* 26 */ + 82, /* 27 */ + 84, /* 28 */ + 85, /* 29 */ + 87, /* 30 */ + 88, /* 31 */ + 90, /* 32 */ + 91, /* 33 */ + 93, /* 34 */ + 94, /* 35 */ + 95, /* 36 */ + 97, /* 37 */ + 98, /* 38 */ + 99, /* 39 */ + 100, /* 40 */ + 102, /* 41 */ + 103, /* 42 */ + 104, /* 43 */ + 105, /* 44 */ + 107, /* 45 */ + 108, /* 46 */ + 109, /* 47 */ + 110, /* 48 */ + 111, /* 49 */ + 112, /* 50 */ + 114, /* 51 */ + 115, /* 52 */ + 116, /* 53 */ + 117, /* 54 */ + 118, /* 55 */ + 119, /* 56 */ + 120, /* 57 */ + 121, /* 58 */ + 122, /* 59 */ + 123, /* 60 */ + 124, /* 61 */ + 125, /* 62 */ + 126, /* 63 */ + 127, /* 64 */ + 128, /* 65 */ + 129, /* 66 */ + 130, /* 67 */ + 131, /* 68 */ + 132, /* 69 */ + 133, /* 70 */ + 134, /* 71 */ + 135, /* 72 */ + 136, /* 73 */ + 137, /* 74 */ + 138, /* 75 */ + 139, /* 76 */ + 140, /* 77 */ + 141, /* 78 */ + 141, /* 79 */ + 142, /* 80 */ + 143, /* 81 */ + 144, /* 82 */ + 145, /* 83 */ + 146, /* 84 */ + 147, /* 85 */ + 148, /* 86 */ + 148, /* 87 */ + 149, /* 88 */ + 150, /* 89 */ + 151, /* 90 */ + 152, /* 91 */ + 153, /* 92 */ + 153, /* 93 */ + 154, /* 94 */ + 155, /* 95 */ + 156, /* 96 */ + 157, /* 97 */ + 158, /* 98 */ + 158, /* 99 */ + 159, /* 100 */ + 160, /* 101 */ + 161, /* 102 */ + 162, /* 103 */ + 162, /* 104 */ + 163, /* 105 */ + 164, /* 106 */ + 165, /* 107 */ + 165, /* 108 */ + 166, /* 109 */ + 167, /* 110 */ + 168, /* 111 */ + 168, /* 112 */ + 169, /* 113 */ + 170, /* 114 */ + 171, /* 115 */ + 171, /* 116 */ + 172, /* 117 */ + 173, /* 118 */ + 174, /* 119 */ + 174, /* 120 */ + 175, /* 121 */ + 176, /* 122 */ + 177, /* 123 */ + 177, /* 124 */ + 178, /* 125 */ + 179, /* 126 */ + 179, /* 127 */ + 180, /* 128 */ + 181, /* 129 */ + 182, /* 130 */ + 182, /* 131 */ + 183, /* 132 */ + 184, /* 133 */ + 184, /* 134 */ + 185, /* 135 */ + 186, /* 136 */ + 186, /* 137 */ + 187, /* 138 */ + 188, /* 139 */ + 188, /* 140 */ + 189, /* 141 */ + 190, /* 142 */ + 190, /* 143 */ + 191, /* 144 */ + 192, /* 145 */ + 192, /* 146 */ + 193, /* 147 */ + 194, /* 148 */ + 194, /* 149 */ + 195, /* 150 */ + 196, /* 151 */ + 196, /* 152 */ + 197, /* 153 */ + 198, /* 154 */ + 198, /* 155 */ + 199, /* 156 */ + 200, /* 157 */ + 200, /* 158 */ + 201, /* 159 */ + 201, /* 160 */ + 202, /* 161 */ + 203, /* 162 */ + 203, /* 163 */ + 204, /* 164 */ + 205, /* 165 */ + 205, /* 166 */ + 206, /* 167 */ + 206, /* 168 */ + 207, /* 169 */ + 208, /* 170 */ + 208, /* 171 */ + 209, /* 172 */ + 210, /* 173 */ + 210, /* 174 */ + 211, /* 175 */ + 211, /* 176 */ + 212, /* 177 */ + 213, /* 178 */ + 213, /* 179 */ + 214, /* 180 */ + 214, /* 181 */ + 215, /* 182 */ + 216, /* 183 */ + 216, /* 184 */ + 217, /* 185 */ + 217, /* 186 */ + 218, /* 187 */ + 218, /* 188 */ + 219, /* 189 */ + 220, /* 190 */ + 220, /* 191 */ + 221, /* 192 */ + 221, /* 193 */ + 222, /* 194 */ + 222, /* 195 */ + 223, /* 196 */ + 224, /* 197 */ + 224, /* 198 */ + 225, /* 199 */ + 225, /* 200 */ + 226, /* 201 */ + 226, /* 202 */ + 227, /* 203 */ + 228, /* 204 */ + 228, /* 205 */ + 229, /* 206 */ + 229, /* 207 */ + 230, /* 208 */ + 230, /* 209 */ + 231, /* 210 */ + 231, /* 211 */ + 232, /* 212 */ + 233, /* 213 */ + 233, /* 214 */ + 234, /* 215 */ + 234, /* 216 */ + 235, /* 217 */ + 235, /* 218 */ + 236, /* 219 */ + 236, /* 220 */ + 237, /* 221 */ + 237, /* 222 */ + 238, /* 223 */ + 238, /* 224 */ + 239, /* 225 */ + 240, /* 226 */ + 240, /* 227 */ + 241, /* 228 */ + 241, /* 229 */ + 242, /* 230 */ + 242, /* 231 */ + 243, /* 232 */ + 243, /* 233 */ + 244, /* 234 */ + 244, /* 235 */ + 245, /* 236 */ + 245, /* 237 */ + 246, /* 238 */ + 246, /* 239 */ + 247, /* 240 */ + 247, /* 241 */ + 248, /* 242 */ + 248, /* 243 */ + 249, /* 244 */ + 249, /* 245 */ + 250, /* 246 */ + 250, /* 247 */ + 251, /* 248 */ + 251, /* 249 */ + 252, /* 250 */ + 252, /* 251 */ + 253, /* 252 */ + 253, /* 253 */ + 254, /* 254 */ + 255 /* 255 */ +}; + +/*! +\brief Internal blitter using adjusted destination alpha during RGBA->RGBA blits. + +Performs the blit based on the 'info' structure and applies the transfer function +to the destination 'a' values. + +\param info The blit info to use. +*/ +void _SDL_gfxBlitBlitterRGBA(SDL_gfxBlitInfo * info) +{ + int width = info->d_width; + int height = info->d_height; + Uint8 *src = info->s_pixels; + int srcskip = info->s_skip; + Uint8 *dst = info->d_pixels; + int dstskip = info->d_skip; + SDL_PixelFormat *srcfmt = info->src; + SDL_PixelFormat *dstfmt = info->dst; + int srcbpp = srcfmt->BytesPerPixel; + int dstbpp = dstfmt->BytesPerPixel; + + while (height--) { + GFX_DUFFS_LOOP4( { + Uint32 pixel; + unsigned sR; + unsigned sG; + unsigned sB; + unsigned sA; + unsigned dR; + unsigned dG; + unsigned dB; + unsigned dA; + unsigned sAA; + GFX_DISEMBLE_RGBA(src, srcbpp, srcfmt, pixel, sR, sG, sB, sA); + GFX_DISEMBLE_RGBA(dst, dstbpp, dstfmt, pixel, dR, dG, dB, dA); + sAA=GFX_ALPHA_ADJUST_ARRAY[sA & 255]; + GFX_ALPHA_BLEND(sR, sG, sB, sAA, dR, dG, dB); + dA |= sAA; + GFX_ASSEMBLE_RGBA(dst, dstbpp, dstfmt, dR, dG, dB, dA); + src += srcbpp; dst += dstbpp; + }, width); + src += srcskip; + dst += dstskip; + } +} + +/*! +\brief Internal blitter setup wrapper for RGBA->RGBA blits. + +Sets up the blitter info based on the 'src' and 'dst' surfaces and rectangles. + +\param src The source surface. +\param srcrect The source rectangle. +\param dst The destination surface. +\param dstrect The destination rectangle. + +\returns Returns 1 if blit was performed, 0 otherwise. +*/ +int _SDL_gfxBlitRGBACall(SDL_Surface * src, SDL_Rect * srcrect, SDL_Surface * dst, SDL_Rect * dstrect) +{ + /* + * Set up source and destination buffer pointers, then blit + */ + if (srcrect->w && srcrect->h) { + SDL_gfxBlitInfo info; + + /* + * Set up the blit information + */ +#if (SDL_MINOR_VERSION == 3) + info.s_pixels = (Uint8 *) src->pixels + (Uint16) srcrect->y * src->pitch + (Uint16) srcrect->x * src->format->BytesPerPixel; +#else + info.s_pixels = (Uint8 *) src->pixels + src->offset + (Uint16) srcrect->y * src->pitch + (Uint16) srcrect->x * src->format->BytesPerPixel; +#endif + info.s_width = srcrect->w; + info.s_height = srcrect->h; + info.s_skip = src->pitch - info.s_width * src->format->BytesPerPixel; +#if (SDL_MINOR_VERSION == 3) + info.d_pixels = (Uint8 *) dst->pixels + (Uint16) dstrect->y * dst->pitch + (Uint16) dstrect->x * dst->format->BytesPerPixel; +#else + info.d_pixels = (Uint8 *) dst->pixels + dst->offset + (Uint16) dstrect->y * dst->pitch + (Uint16) dstrect->x * dst->format->BytesPerPixel; +#endif + info.d_width = dstrect->w; + info.d_height = dstrect->h; + info.d_skip = dst->pitch - info.d_width * dst->format->BytesPerPixel; + info.aux_data = NULL; + info.src = src->format; + info.table = NULL; + info.dst = dst->format; + + /* + * Run the actual software blitter + */ + _SDL_gfxBlitBlitterRGBA(&info); + return 1; + } + + return (0); +} + +/*! +\brief Blitter for RGBA->RGBA blits with alpha adjustment. + +Verifies the input 'src' and 'dst' surfaces and rectangles and performs blit. +The destination clip rectangle is honored. + +\param src The source surface. +\param srcrect The source rectangle. +\param dst The destination surface. +\param dstrect The destination rectangle. + +\returns Returns 1 if blit was performed, 0 otherwise, or -1 if an error occured. +*/ +int SDL_gfxBlitRGBA(SDL_Surface * src, SDL_Rect * srcrect, SDL_Surface * dst, SDL_Rect * dstrect) +{ + SDL_Rect sr, dr; + int srcx, srcy, w, h; + + /* + * Make sure the surfaces aren't locked + */ + if (!src || !dst) { + SDL_SetError("SDL_UpperBlit: passed a NULL surface"); + return (-1); + } + if (src->locked || dst->locked) { + SDL_SetError("Surfaces must not be locked during blit"); + return (-1); + } + + /* + * If the destination rectangle is NULL, use the entire dest surface + */ + if (dstrect == NULL) { + dr.x = dr.y = 0; + dr.w = dst->w; + dr.h = dst->h; + } else { + dr = *dstrect; + } + + /* + * Clip the source rectangle to the source surface + */ + if (srcrect) { + int maxw, maxh; + + srcx = srcrect->x; + w = srcrect->w; + if (srcx < 0) { + w += srcx; + dr.x -= srcx; + srcx = 0; + } + maxw = src->w - srcx; + if (maxw < w) + w = maxw; + + srcy = srcrect->y; + h = srcrect->h; + if (srcy < 0) { + h += srcy; + dr.y -= srcy; + srcy = 0; + } + maxh = src->h - srcy; + if (maxh < h) + h = maxh; + + } else { + srcx = srcy = 0; + w = src->w; + h = src->h; + } + + /* + * Clip the destination rectangle against the clip rectangle + */ + { + SDL_Rect *clip = &dst->clip_rect; + int dx, dy; + + dx = clip->x - dr.x; + if (dx > 0) { + w -= dx; + dr.x += dx; + srcx += dx; + } + dx = dr.x + w - clip->x - clip->w; + if (dx > 0) + w -= dx; + + dy = clip->y - dr.y; + if (dy > 0) { + h -= dy; + dr.y += dy; + srcy += dy; + } + dy = dr.y + h - clip->y - clip->h; + if (dy > 0) + h -= dy; + } + + if (w > 0 && h > 0) { + sr.x = srcx; + sr.y = srcy; + sr.w = dr.w = w; + sr.h = dr.h = h; + return (_SDL_gfxBlitRGBACall(src, &sr, dst, &dr)); + } + + return 0; +} + +/*! +\brief Sets the alpha channel in a 32 bit surface. + +Helper function that sets the alpha channel in a 32 bit surface +to a constant value. +Only 32 bit surfaces can be used with this function. + +\param src Pointer to the target surface to change. +\param a The alpha value to set. + +\return Returns 1 if alpha was changed, 0 otherwise. +*/ +int SDL_gfxSetAlpha(SDL_Surface *src, Uint8 a) +{ +#if SDL_BYTEORDER == SDL_BIG_ENDIAN + Uint16 alpha_offset = 0; +#else + Uint16 alpha_offset = 3; +#endif + Uint16 i, j; + + /* Check if we have a 32bit surface */ + if ( (src) && (src->format) && (src->format->BytesPerPixel==4) ) { + /* Lock and process */ + if ( SDL_LockSurface(src) == 0 ) { + Uint8 *pixels = (Uint8 *)src->pixels; + Uint16 row_skip = (src->pitch - (4*src->w)); + pixels += alpha_offset; + for ( i=0; ih; i++ ) { + for ( j=0; jw; j++ ) { + *pixels = a; + pixels += 4; + } + pixels += row_skip; + } + SDL_UnlockSurface(src); + } + return 1; + } else { + return 0; + } +} + +/*! +\brief Multiply the alpha channel in a 32bit surface. + +Helper function that multiplies the alpha channel in a 32 bit surface +with a constant value. The final alpha is always scaled to the range +0-255 (i.e. the factor is a/256). +Only 32 bit surfaces can be used with this function. + +\param src Pointer to the target surface to change. +\param a The alpha value to multiply with. + +\return Returns 1 if alpha was changed, 0 otherwise. +*/ +int SDL_gfxMultiplyAlpha(SDL_Surface *src, Uint8 a) +{ +#if SDL_BYTEORDER == SDL_BIG_ENDIAN + Uint16 alpha_offset = 0; +#else + Uint16 alpha_offset = 3; +#endif + Uint16 i, j; + + /* Check if we have a 32bit surface */ + if ( (src) && (src->format) && (src->format->BytesPerPixel==4) && (a!=255) ) { + /* Lock and process */ + if ( SDL_LockSurface(src) == 0 ) { + Uint8 *pixels = (Uint8 *)src->pixels; + Uint16 row_skip = (src->pitch - (4*src->w)); + pixels += alpha_offset; + for ( i=0; ih; i++ ) { + for ( j=0; jw; j++ ) { + *pixels = (Uint8)(((int)(*pixels)*a)>>8); + pixels += 4; + } + pixels += row_skip; + } + SDL_UnlockSurface(src); + } + return 1; + } + + return 0; +} diff --git a/engines/vileVN/external/SDL/gfx/SDL_gfxBlitFunc.h b/engines/vileVN/external/SDL/gfx/SDL_gfxBlitFunc.h new file mode 100644 index 0000000000..2690de17c4 --- /dev/null +++ b/engines/vileVN/external/SDL/gfx/SDL_gfxBlitFunc.h @@ -0,0 +1,144 @@ +/* + +SDL_gfxBlitFunc: custom blitters (part of SDL_gfx library) + +LGPL (c) A. Schiffler + +*/ + +#ifndef _SDL_gfxBlitFunc_h +#define _SDL_gfxBlitFunc_h + +/* Set up for C function definitions, even when using C++ */ +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#include +#include + + /* ---- Function Prototypes */ + +#if defined(WIN32) || defined(WIN64) +# if defined(DLL_EXPORT) && !defined(LIBSDL_GFX_DLL_IMPORT) +# define SDL_GFXBLITFUNC_SCOPE __declspec(dllexport) +# else +# ifdef LIBSDL_GFX_DLL_IMPORT +# define SDL_GFXBLITFUNC_SCOPE __declspec(dllimport) +# endif +# endif +#endif +#ifndef SDL_GFXBLITFUNC_SCOPE +# define SDL_GFXBLITFUNC_SCOPE extern +#endif + + + SDL_GFXBLITFUNC_SCOPE int SDL_gfxBlitRGBA(SDL_Surface * src, SDL_Rect * srcrect, SDL_Surface * dst, SDL_Rect * dstrect); + + SDL_GFXBLITFUNC_SCOPE int SDL_gfxSetAlpha(SDL_Surface * src, Uint8 a); + + SDL_GFXBLITFUNC_SCOPE int SDL_gfxMultiplyAlpha(SDL_Surface * src, Uint8 a); + + /* -------- Macros */ + + /* Define SDL macros locally as a substitute for an #include "SDL_blit.h", */ + /* which doesn't work since the include file doesn't get installed. */ + +/*! +\brief The structure passed to the low level blit functions. +*/ + typedef struct { + Uint8 *s_pixels; + int s_width; + int s_height; + int s_skip; + Uint8 *d_pixels; + int d_width; + int d_height; + int d_skip; + void *aux_data; + SDL_PixelFormat *src; + Uint8 *table; + SDL_PixelFormat *dst; + } SDL_gfxBlitInfo; + +/*! +\brief Unwrap RGBA values from a pixel using mask, shift and loss for surface. +*/ +#define GFX_RGBA_FROM_PIXEL(pixel, fmt, r, g, b, a) \ + { \ + r = ((pixel&fmt->Rmask)>>fmt->Rshift)<Rloss; \ + g = ((pixel&fmt->Gmask)>>fmt->Gshift)<Gloss; \ + b = ((pixel&fmt->Bmask)>>fmt->Bshift)<Bloss; \ + a = ((pixel&fmt->Amask)>>fmt->Ashift)<Aloss; \ + } + +/*! +\brief Disassemble buffer pointer into a pixel and separate RGBA values. +*/ +#define GFX_DISEMBLE_RGBA(buf, bpp, fmt, pixel, r, g, b, a) \ + do { \ + pixel = *((Uint32 *)(buf)); \ + GFX_RGBA_FROM_PIXEL(pixel, fmt, r, g, b, a); \ + pixel &= ~fmt->Amask; \ + } while(0) + +/*! +\brief Wrap a pixel from RGBA values using mask, shift and loss for surface. +*/ +#define GFX_PIXEL_FROM_RGBA(pixel, fmt, r, g, b, a) \ + { \ + pixel = ((r>>fmt->Rloss)<Rshift)| \ + ((g>>fmt->Gloss)<Gshift)| \ + ((b>>fmt->Bloss)<Bshift)| \ + ((a<Aloss)<Ashift); \ + } + +/*! +\brief Assemble pixel into buffer pointer from separate RGBA values. +*/ +#define GFX_ASSEMBLE_RGBA(buf, bpp, fmt, r, g, b, a) \ + { \ + Uint32 pixel; \ + \ + GFX_PIXEL_FROM_RGBA(pixel, fmt, r, g, b, a); \ + *((Uint32 *)(buf)) = pixel; \ + } + +/*! +\brief Blend the RGB values of two pixels based on a source alpha value. +*/ +#define GFX_ALPHA_BLEND(sR, sG, sB, A, dR, dG, dB) \ + do { \ + dR = (((sR-dR)*(A))/255)+dR; \ + dG = (((sG-dG)*(A))/255)+dG; \ + dB = (((sB-dB)*(A))/255)+dB; \ + } while(0) + +/*! +\brief 4-times unrolled DUFFs loop. + +This is a very useful loop for optimizing blitters. +*/ +#define GFX_DUFFS_LOOP4(pixel_copy_increment, width) \ + { int n = (width+3)/4; \ + switch (width & 3) { \ + case 0: do { pixel_copy_increment; \ + case 3: pixel_copy_increment; \ + case 2: pixel_copy_increment; \ + case 1: pixel_copy_increment; \ + } while ( --n > 0 ); \ + } \ + } + + + + /* Ends C function definitions when using C++ */ +#ifdef __cplusplus +} +#endif + +#endif /* _SDL_gfxBlitFunc_h */ diff --git a/engines/vileVN/external/SDL/gfx/SDL_gfxPrimitives.c b/engines/vileVN/external/SDL/gfx/SDL_gfxPrimitives.c new file mode 100644 index 0000000000..a59db1b69a --- /dev/null +++ b/engines/vileVN/external/SDL/gfx/SDL_gfxPrimitives.c @@ -0,0 +1,6755 @@ +/* + +SDL_gfxPrimitives - Graphics primitives for SDL surfaces + +LGPL (c) A. Schiffler + +*/ + +#include +#include +#include +#include + +#include "SDL_gfxPrimitives.h" +#include "SDL_rotozoom.h" +#include "SDL_gfxPrimitives_font.h" + +/* -===================- */ + +#define DEFAULT_ALPHA_PIXEL_ROUTINE +#undef EXPERIMENTAL_ALPHA_PIXEL_ROUTINE + +/* ---- Structures */ + +/*! +\brief The structure passed to the internal Bresenham iterator. +*/ +typedef struct { + Sint16 x, y; + int dx, dy, s1, s2, swapdir, error; + Uint32 count; +} SDL_gfxBresenhamIterator; + +/*! +\brief The structure passed to the internal Murphy iterator. +*/ +typedef struct { + Uint32 color; + SDL_Surface *dst; + int u, v; /* delta x , delta y */ + int ku, kt, kv, kd; /* loop constants */ + int oct2; + int quad4; + Sint16 last1x, last1y, last2x, last2y, first1x, first1y, first2x, first2y, tempx, tempy; +} SDL_gfxMurphyIterator; + +/* ----- Defines for pixel clipping tests */ + +#define clip_xmin(surface) surface->clip_rect.x +#define clip_xmax(surface) surface->clip_rect.x+surface->clip_rect.w-1 +#define clip_ymin(surface) surface->clip_rect.y +#define clip_ymax(surface) surface->clip_rect.y+surface->clip_rect.h-1 + +/*! +\brief Internal pixel drawing - fast, no blending, no locking, clipping. + +\param dst The surface to draw on. +\param x The horizontal coordinate of the pixel. +\param y The vertical position of the pixel. +\param color The color value of the pixel to draw. + +\returns Returns 0 on success, -1 on failure. +*/ +int fastPixelColorNolock(SDL_Surface * dst, Sint16 x, Sint16 y, Uint32 color) +{ + int bpp; + Uint8 *p; + + /* + * Honor clipping setup at pixel level + */ + if ((x >= clip_xmin(dst)) && (x <= clip_xmax(dst)) && (y >= clip_ymin(dst)) && (y <= clip_ymax(dst))) { + + /* + * Get destination format + */ + bpp = dst->format->BytesPerPixel; + p = (Uint8 *) dst->pixels + y * dst->pitch + x * bpp; + switch (bpp) { + case 1: + *p = color; + break; + case 2: + *(Uint16 *) p = color; + break; + case 3: + if (SDL_BYTEORDER == SDL_BIG_ENDIAN) { + p[0] = (color >> 16) & 0xff; + p[1] = (color >> 8) & 0xff; + p[2] = color & 0xff; + } else { + p[0] = color & 0xff; + p[1] = (color >> 8) & 0xff; + p[2] = (color >> 16) & 0xff; + } + break; + case 4: + *(Uint32 *) p = color; + break; + } /* switch */ + + + } + + return (0); +} + +/*! +\brief Internal pixel drawing - fast, no blending, no locking, no clipping. + +Function is faster but dangerous since no clipping check is done. +Code needs to make sure we stay in surface bounds before calling. + +\param dst The surface to draw on. +\param x The horizontal coordinate of the pixel. +\param y The vertical position of the pixel. +\param color The color value of the pixel to draw. + +\returns Returns 0 on success, -1 on failure. +*/ +int fastPixelColorNolockNoclip(SDL_Surface * dst, Sint16 x, Sint16 y, Uint32 color) +{ + int bpp; + Uint8 *p; + + /* + * Get destination format + */ + bpp = dst->format->BytesPerPixel; + p = (Uint8 *) dst->pixels + y * dst->pitch + x * bpp; + switch (bpp) { + case 1: + *p = color; + break; + case 2: + *(Uint16 *) p = color; + break; + case 3: + if (SDL_BYTEORDER == SDL_BIG_ENDIAN) { + p[0] = (color >> 16) & 0xff; + p[1] = (color >> 8) & 0xff; + p[2] = color & 0xff; + } else { + p[0] = color & 0xff; + p[1] = (color >> 8) & 0xff; + p[2] = (color >> 16) & 0xff; + } + break; + case 4: + *(Uint32 *) p = color; + break; + } /* switch */ + + return (0); +} + +/*! +\brief Internal pixel drawing - fast, no blending, locking, clipping. + +\param dst The surface to draw on. +\param x The horizontal coordinate of the pixel. +\param y The vertical position of the pixel. +\param color The color value of the pixel to draw. + +\returns Returns 0 on success, -1 on failure. +*/ +int fastPixelColor(SDL_Surface * dst, Sint16 x, Sint16 y, Uint32 color) +{ + int result; + + /* + * Lock the surface + */ + if (SDL_MUSTLOCK(dst)) { + if (SDL_LockSurface(dst) < 0) { + return (-1); + } + } + + result = fastPixelColorNolock(dst, x, y, color); + + /* + * Unlock surface + */ + if (SDL_MUSTLOCK(dst)) { + SDL_UnlockSurface(dst); + } + + return (result); +} + +/*! +\brief Internal pixel drawing - fast, no blending, locking, RGB input. + +\param dst The surface to draw on. +\param x The horizontal coordinate of the pixel. +\param y The vertical position of the pixel. +\param r The red value of the pixel to draw. +\param g The green value of the pixel to draw. +\param b The blue value of the pixel to draw. +\param a The alpha value of the pixel to draw. + +\returns Returns 0 on success, -1 on failure. +*/ +int fastPixelRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + Uint32 color; + + /* + * Setup color + */ + color = SDL_MapRGBA(dst->format, r, g, b, a); + + /* + * Draw + */ + return (fastPixelColor(dst, x, y, color)); +} + +/*! +\brief Internal pixel drawing - fast, no blending, no locking RGB input. + +\param dst The surface to draw on. +\param x The horizontal coordinate of the pixel. +\param y The vertical position of the pixel. +\param r The red value of the pixel to draw. +\param g The green value of the pixel to draw. +\param b The blue value of the pixel to draw. +\param a The alpha value of the pixel to draw. + +\returns Returns 0 on success, -1 on failure. +*/ +int fastPixelRGBANolock(SDL_Surface * dst, Sint16 x, Sint16 y, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + Uint32 color; + + /* + * Setup color + */ + color = SDL_MapRGBA(dst->format, r, g, b, a); + + /* + * Draw + */ + return (fastPixelColorNolock(dst, x, y, color)); +} + +/*! +\brief Internal pixel drawing function with alpha blending where input color in in destination format. + +Contains two alternative 32 bit alpha blending routines which can be enabled at the source +level with the defines DEFAULT_ALPHA_PIXEL_ROUTINE or EXPERIMENTAL_ALPHA_PIXEL_ROUTINE. +Only the bits up to the surface depth are significant in the color value. + +\param dst The surface to draw on. +\param x The horizontal coordinate of the pixel. +\param y The vertical position of the pixel. +\param color The color value of the pixel to draw. +\param alpha The blend factor to apply while drawing. + +\returns Returns 0 on success, -1 on failure. +*/ +int _putPixelAlpha(SDL_Surface *dst, Sint16 x, Sint16 y, Uint32 color, Uint8 alpha) +{ + SDL_PixelFormat *format; + Uint32 Rmask, Gmask, Bmask, Amask; + Uint32 Rshift, Gshift, Bshift, Ashift; + Uint32 R, G, B, A; + + if (dst == NULL) + { + return (-1); + } + + if (x >= clip_xmin(dst) && x <= clip_xmax(dst) && + y >= clip_ymin(dst) && y <= clip_ymax(dst)) + { + + format = dst->format; + + switch (format->BytesPerPixel) { + case 1: + { /* Assuming 8-bpp */ + if (alpha == 255) { + *((Uint8 *) dst->pixels + y * dst->pitch + x) = color; + } else { + Uint8 *pixel = (Uint8 *) dst->pixels + y * dst->pitch + x; + SDL_Palette *palette = format->palette; + SDL_Color *colors = palette->colors; + SDL_Color dColor = colors[*pixel]; + SDL_Color sColor = colors[color]; + Uint8 dR = dColor.r; + Uint8 dG = dColor.g; + Uint8 dB = dColor.b; + Uint8 sR = sColor.r; + Uint8 sG = sColor.g; + Uint8 sB = sColor.b; + + dR = dR + ((sR - dR) * alpha >> 8); + dG = dG + ((sG - dG) * alpha >> 8); + dB = dB + ((sB - dB) * alpha >> 8); + + *pixel = SDL_MapRGB(format, dR, dG, dB); + } + } + break; + + case 2: + { /* Probably 15-bpp or 16-bpp */ + if (alpha == 255) { + *((Uint16 *) dst->pixels + y * dst->pitch / 2 + x) = color; + } else { + Uint16 *pixel = (Uint16 *) dst->pixels + y * dst->pitch / 2 + x; + Uint32 dc = *pixel; + + Rmask = format->Rmask; + Gmask = format->Gmask; + Bmask = format->Bmask; + Amask = format->Amask; + R = ((dc & Rmask) + (((color & Rmask) - (dc & Rmask)) * alpha >> 8)) & Rmask; + G = ((dc & Gmask) + (((color & Gmask) - (dc & Gmask)) * alpha >> 8)) & Gmask; + B = ((dc & Bmask) + (((color & Bmask) - (dc & Bmask)) * alpha >> 8)) & Bmask; + if (Amask) { + A = ((dc & Amask) + (((color & Amask) - (dc & Amask)) * alpha >> 8)) & Amask; + } + *pixel = R | G | B | A; + } + } + break; + + case 3: + { /* Slow 24-bpp mode, usually not used */ + Uint8 Rshift8, Gshift8, Bshift8, Ashift8; + Uint8 *pixel = (Uint8 *) dst->pixels + y * dst->pitch + x * 3; + + Rshift = format->Rshift; + Gshift = format->Gshift; + Bshift = format->Bshift; + Ashift = format->Ashift; + + Rshift8 = Rshift / 8; + Gshift8 = Gshift / 8; + Bshift8 = Bshift / 8; + Ashift8 = Ashift / 8; + + if (alpha == 255) { + *(pixel + Rshift8) = color >> Rshift; + *(pixel + Gshift8) = color >> Gshift; + *(pixel + Bshift8) = color >> Bshift; + *(pixel + Ashift8) = color >> Ashift; + } else { + Uint8 dR, dG, dB, dA = 0; + Uint8 sR, sG, sB, sA = 0; + + dR = *((pixel) + Rshift8); + dG = *((pixel) + Gshift8); + dB = *((pixel) + Bshift8); + dA = *((pixel) + Ashift8); + + sR = (color >> Rshift) & 0xff; + sG = (color >> Gshift) & 0xff; + sB = (color >> Bshift) & 0xff; + sA = (color >> Ashift) & 0xff; + + dR = dR + ((sR - dR) * alpha >> 8); + dG = dG + ((sG - dG) * alpha >> 8); + dB = dB + ((sB - dB) * alpha >> 8); + dA = dA + ((sA - dA) * alpha >> 8); + + *((pixel) + Rshift8) = dR; + *((pixel) + Gshift8) = dG; + *((pixel) + Bshift8) = dB; + *((pixel) + Ashift8) = dA; + } + } + break; + +#ifdef DEFAULT_ALPHA_PIXEL_ROUTINE + + case 4: + { /* Probably :-) 32-bpp */ + if (alpha == 255) { + *((Uint32 *) dst->pixels + y * dst->pitch / 4 + x) = color; + } else { + Uint32 *pixel = (Uint32 *) dst->pixels + y * dst->pitch / 4 + x; + Uint32 dc = *pixel; + + Rmask = format->Rmask; + Gmask = format->Gmask; + Bmask = format->Bmask; + Amask = format->Amask; + + Rshift = format->Rshift; + Gshift = format->Gshift; + Bshift = format->Bshift; + Ashift = format->Ashift; + + A = 0; + R = ((dc & Rmask) + (((((color & Rmask) - (dc & Rmask)) >> Rshift) * alpha >> 8) << Rshift)) & Rmask; + G = ((dc & Gmask) + (((((color & Gmask) - (dc & Gmask)) >> Gshift) * alpha >> 8) << Gshift)) & Gmask; + B = ((dc & Bmask) + (((((color & Bmask) - (dc & Bmask)) >> Bshift) * alpha >> 8) << Bshift)) & Bmask; + if (Amask) { + A = ((dc & Amask) + (((((color & Amask) - (dc & Amask)) >> Ashift) * alpha >> 8) << Ashift)) & Amask; + } + *pixel = R | G | B | A; + } + } + break; +#endif + +#ifdef EXPERIMENTAL_ALPHA_PIXEL_ROUTINE + + case 4:{ /* Probably :-) 32-bpp */ + if (alpha == 255) { + *((Uint32 *) dst->pixels + y * dst->pitch / 4 + x) = color; + } else { + Uint32 *pixel = (Uint32 *) dst->pixels + y * dst->pitch / 4 + x; + Uint32 dR, dG, dB, dA; + Uint32 dc = *pixel; + + Uint32 surfaceAlpha, preMultR, preMultG, preMultB; + Uint32 aTmp; + + Rmask = format->Rmask; + Gmask = format->Gmask; + Bmask = format->Bmask; + Amask = format->Amask; + + dR = (color & Rmask); + dG = (color & Gmask); + dB = (color & Bmask); + dA = (color & Amask); + + Rshift = format->Rshift; + Gshift = format->Gshift; + Bshift = format->Bshift; + Ashift = format->Ashift; + + preMultR = (alpha * (dR >> Rshift)); + preMultG = (alpha * (dG >> Gshift)); + preMultB = (alpha * (dB >> Bshift)); + + surfaceAlpha = ((dc & Amask) >> Ashift); + aTmp = (255 - alpha); + if (A = 255 - ((aTmp * (255 - surfaceAlpha)) >> 8 )) { + aTmp *= surfaceAlpha; + R = (preMultR + ((aTmp * ((dc & Rmask) >> Rshift)) >> 8)) / A << Rshift & Rmask; + G = (preMultG + ((aTmp * ((dc & Gmask) >> Gshift)) >> 8)) / A << Gshift & Gmask; + B = (preMultB + ((aTmp * ((dc & Bmask) >> Bshift)) >> 8)) / A << Bshift & Bmask; + } + *pixel = R | G | B | (A << Ashift & Amask); + + } + } + break; +#endif + } + } + + return (0); +} + +/*! +\brief Pixel draw with blending enabled if a<255. + +\param dst The surface to draw on. +\param x X (horizontal) coordinate of the pixel. +\param y Y (vertical) coordinate of the pixel. +\param color The color value of the pixel to draw (0xRRGGBBAA). + +\returns Returns 0 on success, -1 on failure. +*/ +int pixelColor(SDL_Surface * dst, Sint16 x, Sint16 y, Uint32 color) +{ + Uint8 alpha; + Uint32 mcolor; + int result = 0; + + /* + * Lock the surface + */ + if (SDL_MUSTLOCK(dst)) { + if (SDL_LockSurface(dst) < 0) { + return (-1); + } + } + + /* + * Setup color + */ + alpha = color & 0x000000ff; + mcolor = + SDL_MapRGBA(dst->format, (color & 0xff000000) >> 24, + (color & 0x00ff0000) >> 16, (color & 0x0000ff00) >> 8, alpha); + + /* + * Draw + */ + result = _putPixelAlpha(dst, x, y, mcolor, alpha); + + /* + * Unlock the surface + */ + if (SDL_MUSTLOCK(dst)) { + SDL_UnlockSurface(dst); + } + + return (result); +} + +/*! +\brief Pixel draw with blending enabled if a<255 - no surface locking. + +\param dst The surface to draw on. +\param x X (horizontal) coordinate of the pixel. +\param y Y (vertical) coordinate of the pixel. +\param color The color value of the pixel to draw (0xRRGGBBAA). + +\returns Returns 0 on success, -1 on failure. +*/ +int pixelColorNolock(SDL_Surface * dst, Sint16 x, Sint16 y, Uint32 color) +{ + Uint8 alpha; + Uint32 mcolor; + int result = 0; + + /* + * Setup color + */ + alpha = color & 0x000000ff; + mcolor = + SDL_MapRGBA(dst->format, (color & 0xff000000) >> 24, + (color & 0x00ff0000) >> 16, (color & 0x0000ff00) >> 8, alpha); + + /* + * Draw + */ + result = _putPixelAlpha(dst, x, y, mcolor, alpha); + + return (result); +} + + +/*! +\brief Internal function to draw filled rectangle with alpha blending. + +Assumes color is in destination format. + +\param dst The surface to draw on. +\param x1 X coordinate of the first corner (upper left) of the rectangle. +\param y1 Y coordinate of the first corner (upper left) of the rectangle. +\param x2 X coordinate of the second corner (lower right) of the rectangle. +\param y2 Y coordinate of the second corner (lower right) of the rectangle. +\param color The color value of the rectangle to draw (0xRRGGBBAA). +\param alpha Alpha blending amount for pixels. + +\returns Returns 0 on success, -1 on failure. +*/ +int _filledRectAlpha(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color, Uint8 alpha) +{ + SDL_PixelFormat *format; + Uint32 Rmask, Bmask, Gmask, Amask; + Uint32 Rshift, Bshift, Gshift, Ashift; + Uint8 sR, sG, sB, sA; + Uint32 R, G, B, A; + Sint16 x, y; + + format = dst->format; + switch (format->BytesPerPixel) { + case 1: + { /* Assuming 8-bpp */ + Uint8 *row, *pixel; + Uint8 dR, dG, dB; + SDL_Palette *palette = format->palette; + SDL_Color *colors = palette->colors; + sR = colors[color].r; + sG = colors[color].g; + sB = colors[color].b; + + for (y = y1; y <= y2; y++) { + row = (Uint8 *) dst->pixels + y * dst->pitch; + for (x = x1; x <= x2; x++) { + pixel = row + x; + + dR = colors[*pixel].r; + dG = colors[*pixel].g; + dB = colors[*pixel].b; + + dR = dR + ((sR - dR) * alpha >> 8); + dG = dG + ((sG - dG) * alpha >> 8); + dB = dB + ((sB - dB) * alpha >> 8); + + *pixel = SDL_MapRGB(format, dR, dG, dB); + } + } + } + break; + + case 2: + { /* Probably 15-bpp or 16-bpp */ + Uint16 *row, *pixel; + Uint32 dR, dG, dB, dA; + Rmask = format->Rmask; + Gmask = format->Gmask; + Bmask = format->Bmask; + Amask = format->Amask; + + dR = (color & Rmask); + dG = (color & Gmask); + dB = (color & Bmask); + dA = (color & Amask); + + A = 0; + + for (y = y1; y <= y2; y++) { + row = (Uint16 *) dst->pixels + y * dst->pitch / 2; + for (x = x1; x <= x2; x++) { + pixel = row + x; + + R = ((*pixel & Rmask) + ((dR - (*pixel & Rmask)) * alpha >> 8)) & Rmask; + G = ((*pixel & Gmask) + ((dG - (*pixel & Gmask)) * alpha >> 8)) & Gmask; + B = ((*pixel & Bmask) + ((dB - (*pixel & Bmask)) * alpha >> 8)) & Bmask; + if (Amask) + { + A = ((*pixel & Amask) + ((dA - (*pixel & Amask)) * alpha >> 8)) & Amask; + *pixel = R | G | B | A; + } else { + *pixel = R | G | B; + } + } + } + } + break; + + case 3: + { /* Slow 24-bpp mode, usually not used */ + Uint8 *row, *pix; + Uint8 dR, dG, dB, dA; + Uint8 Rshift8, Gshift8, Bshift8, Ashift8; + + Rshift = format->Rshift; + Gshift = format->Gshift; + Bshift = format->Bshift; + Ashift = format->Ashift; + + Rshift8 = Rshift / 8; + Gshift8 = Gshift / 8; + Bshift8 = Bshift / 8; + Ashift8 = Ashift / 8; + + sR = (color >> Rshift) & 0xff; + sG = (color >> Gshift) & 0xff; + sB = (color >> Bshift) & 0xff; + sA = (color >> Ashift) & 0xff; + + for (y = y1; y <= y2; y++) { + row = (Uint8 *) dst->pixels + y * dst->pitch; + for (x = x1; x <= x2; x++) { + pix = row + x * 3; + + dR = *((pix) + Rshift8); + dG = *((pix) + Gshift8); + dB = *((pix) + Bshift8); + dA = *((pix) + Ashift8); + + dR = dR + ((sR - dR) * alpha >> 8); + dG = dG + ((sG - dG) * alpha >> 8); + dB = dB + ((sB - dB) * alpha >> 8); + dA = dA + ((sA - dA) * alpha >> 8); + + *((pix) + Rshift8) = dR; + *((pix) + Gshift8) = dG; + *((pix) + Bshift8) = dB; + *((pix) + Ashift8) = dA; + } + } + } + break; + +#ifdef DEFAULT_ALPHA_PIXEL_ROUTINE + case 4: + { /* Probably :-) 32-bpp */ + Uint32 *row, *pixel; + Uint32 dR, dG, dB, dA; + + Rmask = format->Rmask; + Gmask = format->Gmask; + Bmask = format->Bmask; + Amask = format->Amask; + + Rshift = format->Rshift; + Gshift = format->Gshift; + Bshift = format->Bshift; + Ashift = format->Ashift; + + dR = (color & Rmask); + dG = (color & Gmask); + dB = (color & Bmask); + dA = (color & Amask); + + for (y = y1; y <= y2; y++) { + row = (Uint32 *) dst->pixels + y * dst->pitch / 4; + for (x = x1; x <= x2; x++) { + pixel = row + x; + + R = ((*pixel & Rmask) + ((((dR - (*pixel & Rmask)) >> Rshift) * alpha >> 8) << Rshift)) & Rmask; + G = ((*pixel & Gmask) + ((((dG - (*pixel & Gmask)) >> Gshift) * alpha >> 8) << Gshift)) & Gmask; + B = ((*pixel & Bmask) + ((((dB - (*pixel & Bmask)) >> Bshift) * alpha >> 8) << Bshift)) & Bmask; + if (Amask) + { + A = ((*pixel & Amask) + ((((dA - (*pixel & Amask)) >> Ashift) * alpha >> 8) << Ashift)) & Amask; + *pixel = R | G | B | A; + } else { + *pixel = R | G | B; + } + } + } + } + break; +#endif + +#ifdef EXPERIMENTAL_ALPHA_PIXEL_ROUTINE + case 4:{ /* Probably :-) 32-bpp */ + Uint32 *row, *pixel; + Uint32 dR, dG, dB, dA; + Uint32 dc; + Uint32 surfaceAlpha, preMultR, preMultG, preMultB; + Uint32 aTmp; + + Rmask = format->Rmask; + Gmask = format->Gmask; + Bmask = format->Bmask; + Amask = format->Amask; + + dR = (color & Rmask); + dG = (color & Gmask); + dB = (color & Bmask); + dA = (color & Amask); + + Rshift = format->Rshift; + Gshift = format->Gshift; + Bshift = format->Bshift; + Ashift = format->Ashift; + + preMultR = (alpha * (dR >> Rshift)); + preMultG = (alpha * (dG >> Gshift)); + preMultB = (alpha * (dB >> Bshift)); + + for (y = y1; y <= y2; y++) { + row = (Uint32 *) dst->pixels + y * dst->pitch / 4; + for (x = x1; x <= x2; x++) { + pixel = row + x; + dc = *pixel; + + surfaceAlpha = ((dc & Amask) >> Ashift); + aTmp = (255 - alpha); + if (A = 255 - ((aTmp * (255 - surfaceAlpha)) >> 8 )) { + aTmp *= surfaceAlpha; + R = (preMultR + ((aTmp * ((dc & Rmask) >> Rshift)) >> 8)) / A << Rshift & Rmask; + G = (preMultG + ((aTmp * ((dc & Gmask) >> Gshift)) >> 8)) / A << Gshift & Gmask; + B = (preMultB + ((aTmp * ((dc & Bmask) >> Bshift)) >> 8)) / A << Bshift & Bmask; + } + *pixel = R | G | B | (A << Ashift & Amask); + + } + } + } + break; +#endif + + } + + return (0); +} + +/*! +\brief Draw filled rectangle of RGBA color with alpha blending. + +\param dst The surface to draw on. +\param x1 X coordinate of the first corner (upper left) of the rectangle. +\param y1 Y coordinate of the first corner (upper left) of the rectangle. +\param x2 X coordinate of the second corner (lower right) of the rectangle. +\param y2 Y coordinate of the second corner (lower right) of the rectangle. +\param color The color value of the rectangle to draw (0xRRGGBBAA). + +\returns Returns 0 on success, -1 on failure. +*/ +int filledRectAlpha(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color) +{ + Uint8 alpha; + Uint32 mcolor; + int result = 0; + + /* + * Lock the surface + */ + if (SDL_MUSTLOCK(dst)) { + if (SDL_LockSurface(dst) < 0) { + return (-1); + } + } + + /* + * Setup color + */ + alpha = color & 0x000000ff; + mcolor = + SDL_MapRGBA(dst->format, (color & 0xff000000) >> 24, + (color & 0x00ff0000) >> 16, (color & 0x0000ff00) >> 8, alpha); + + /* + * Draw + */ + result = _filledRectAlpha(dst, x1, y1, x2, y2, mcolor, alpha); + + /* + * Unlock the surface + */ + if (SDL_MUSTLOCK(dst)) { + SDL_UnlockSurface(dst); + } + + return (result); +} + +/*! +\brief Internal function to draw horizontal line of RGBA color with alpha blending. + +\param dst The surface to draw on. +\param x1 X coordinate of the first point (i.e. left) of the line. +\param x2 X coordinate of the second point (i.e. right) of the line. +\param y Y coordinate of the points of the line. +\param color The color value of the line to draw (0xRRGGBBAA). + +\returns Returns 0 on success, -1 on failure. +*/ +int _HLineAlpha(SDL_Surface * dst, Sint16 x1, Sint16 x2, Sint16 y, Uint32 color) +{ + return (filledRectAlpha(dst, x1, y, x2, y, color)); +} + +/*! +\brief Internal function to draw vertical line of RGBA color with alpha blending. + +\param dst The surface to draw on. +\param x X coordinate of the points of the line. +\param y1 Y coordinate of the first point (top) of the line. +\param y2 Y coordinate of the second point (bottom) of the line. +\param color The color value of the line to draw (0xRRGGBBAA). + +\returns Returns 0 on success, -1 on failure. +*/ +int _VLineAlpha(SDL_Surface * dst, Sint16 x, Sint16 y1, Sint16 y2, Uint32 color) +{ + return (filledRectAlpha(dst, x, y1, x, y2, color)); +} + +/*! +\brief Pixel draw with blending enabled and using alpha weight on color. + +\param dst The surface to draw on. +\param x The horizontal coordinate of the pixel. +\param y The vertical position of the pixel. +\param color The color value of the pixel to draw (0xRRGGBBAA). +\param weight The weight multiplied into the alpha value of the pixel. + +\returns Returns 0 on success, -1 on failure. +*/ +int pixelColorWeight(SDL_Surface * dst, Sint16 x, Sint16 y, Uint32 color, Uint32 weight) +{ + Uint32 a; + + /* + * Get alpha + */ + a = (color & (Uint32) 0x000000ff); + + /* + * Modify Alpha by weight + */ + a = ((a * weight) >> 8); + + return (pixelColor(dst, x, y, (color & (Uint32) 0xffffff00) | (Uint32) a)); +} + +/*! +\brief Pixel draw with blending enabled and using alpha weight on color - no locking. + +\param dst The surface to draw on. +\param x The horizontal coordinate of the pixel. +\param y The vertical position of the pixel. +\param color The color value of the pixel to draw (0xRRGGBBAA). +\param weight The weight multiplied into the alpha value of the pixel. + +\returns Returns 0 on success, -1 on failure. +*/ +int pixelColorWeightNolock(SDL_Surface * dst, Sint16 x, Sint16 y, Uint32 color, Uint32 weight) +{ + Uint32 a; + + /* + * Get alpha + */ + a = (color & (Uint32) 0x000000ff); + + /* + * Modify Alpha by weight + */ + a = ((a * weight) >> 8); + + return (pixelColorNolock(dst, x, y, (color & (Uint32) 0xffffff00) | (Uint32) a)); +} + +/*! +\brief Pixel draw with blending enabled if a<255. + +\param dst The surface to draw on. +\param x X (horizontal) coordinate of the pixel. +\param y Y (vertical) coordinate of the pixel. +\param r The red color value of the pixel to draw. +\param g The green color value of the pixel to draw. +\param b The blue color value of the pixel to draw. +\param a The alpha value of the pixel to draw. + +\returns Returns 0 on success, -1 on failure. +*/ +int pixelRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + Uint32 color; + + /* + * Check Alpha + */ + if (a == 255) { + /* + * No alpha blending required + */ + /* + * Setup color + */ + color = SDL_MapRGBA(dst->format, r, g, b, a); + /* + * Draw + */ + return (fastPixelColor(dst, x, y, color)); + } else { + /* + * Alpha blending required + */ + /* + * Draw + */ + return (pixelColor(dst, x, y, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a)); + } +} + + +/*! +\brief Draw horizontal line without blending; + +Just stores the color value (including the alpha component) without blending. +Only the same number of bits of the destination surface are transfered +from the input color value. + +\param dst The surface to draw on. +\param x1 X coordinate of the first point (i.e. left) of the line. +\param x2 X coordinate of the second point (i.e. right) of the line. +\param y Y coordinate of the points of the line. +\param color The color value of the line to draw. + +\returns Returns 0 on success, -1 on failure. +*/ +int hlineColorStore(SDL_Surface * dst, Sint16 x1, Sint16 x2, Sint16 y, Uint32 color) +{ + Sint16 left, right, top, bottom; + Uint8 *pixel, *pixellast; + int dx; + int pixx, pixy; + Sint16 w; + Sint16 xtmp; + int result = -1; + + /* + * Check visibility of clipping rectangle + */ + if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) { + return(0); + } + + /* + * Swap x1, x2 if required to ensure x1<=x2 + */ + if (x1 > x2) { + xtmp = x1; + x1 = x2; + x2 = xtmp; + } + + /* + * Get clipping boundary and + * check visibility of hline + */ + left = dst->clip_rect.x; + if (x2clip_rect.x + dst->clip_rect.w - 1; + if (x1>right) { + return(0); + } + top = dst->clip_rect.y; + bottom = dst->clip_rect.y + dst->clip_rect.h - 1; + if ((ybottom)) { + return (0); + } + + /* + * Clip x + */ + if (x1 < left) { + x1 = left; + } + if (x2 > right) { + x2 = right; + } + + /* + * Calculate width + */ + w = x2 - x1; + + /* + * Lock the surface + */ + if (SDL_MUSTLOCK(dst)) { + if (SDL_LockSurface(dst) < 0) { + return (-1); + } + } + + /* + * More variable setup + */ + dx = w; + pixx = dst->format->BytesPerPixel; + pixy = dst->pitch; + pixel = ((Uint8 *) dst->pixels) + pixx * (int) x1 + pixy * (int) y; + + /* + * Draw + */ + switch (dst->format->BytesPerPixel) { + case 1: + memset(pixel, color, dx+1); + break; + case 2: + pixellast = pixel + dx + dx; + for (; pixel <= pixellast; pixel += pixx) { + *(Uint16 *) pixel = color; + } + break; + case 3: + pixellast = pixel + dx + dx + dx; + for (; pixel <= pixellast; pixel += pixx) { + if (SDL_BYTEORDER == SDL_BIG_ENDIAN) { + pixel[0] = (color >> 16) & 0xff; + pixel[1] = (color >> 8) & 0xff; + pixel[2] = color & 0xff; + } else { + pixel[0] = color & 0xff; + pixel[1] = (color >> 8) & 0xff; + pixel[2] = (color >> 16) & 0xff; + } + } + break; + default: /* case 4 */ + dx = dx + dx; + pixellast = pixel + dx + dx; + for (; pixel <= pixellast; pixel += pixx) { + *(Uint32 *) pixel = color; + } + break; + } + + /* + * Unlock surface + */ + if (SDL_MUSTLOCK(dst)) { + SDL_UnlockSurface(dst); + } + + /* + * Set result code + */ + result = 0; + + return (result); +} + +/*! +\brief Draw horizontal line without blending + +Just stores the color value (including the alpha component) without blending. +Function should only be used for 32 bit target surfaces. + +\param dst The surface to draw on. +\param x1 X coordinate of the first point (i.e. left) of the line. +\param x2 X coordinate of the second point (i.e. right) of the line. +\param y Y coordinate of the points of the line. +\param r The red value of the line to draw. +\param g The green value of the line to draw. +\param b The blue value of the line to draw. +\param a The alpha value of the line to draw. + +\returns Returns 0 on success, -1 on failure. +*/ +int hlineRGBAStore(SDL_Surface * dst, Sint16 x1, Sint16 x2, Sint16 y, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + /* + * Draw + */ + return (hlineColorStore(dst, x1, x2, y, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a)); +} + +/*! +\brief Draw horizontal line with blending. + +\param dst The surface to draw on. +\param x1 X coordinate of the first point (i.e. left) of the line. +\param x2 X coordinate of the second point (i.e. right) of the line. +\param y Y coordinate of the points of the line. +\param color The color value of the line to draw (0xRRGGBBAA). + +\returns Returns 0 on success, -1 on failure. +*/ +int hlineColor(SDL_Surface * dst, Sint16 x1, Sint16 x2, Sint16 y, Uint32 color) +{ + Sint16 left, right, top, bottom; + Uint8 *pixel, *pixellast; + int dx; + int pixx, pixy; + Sint16 xtmp; + int result = -1; + Uint8 *colorptr; + Uint8 color3[3]; + + /* + * Check visibility of clipping rectangle + */ + if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) { + return(0); + } + + /* + * Swap x1, x2 if required to ensure x1<=x2 + */ + if (x1 > x2) { + xtmp = x1; + x1 = x2; + x2 = xtmp; + } + + /* + * Get clipping boundary and + * check visibility of hline + */ + left = dst->clip_rect.x; + if (x2clip_rect.x + dst->clip_rect.w - 1; + if (x1>right) { + return(0); + } + top = dst->clip_rect.y; + bottom = dst->clip_rect.y + dst->clip_rect.h - 1; + if ((ybottom)) { + return (0); + } + + /* + * Clip x + */ + if (x1 < left) { + x1 = left; + } + if (x2 > right) { + x2 = right; + } + + /* + * Calculate width difference + */ + dx = x2 - x1; + + /* + * Alpha check + */ + if ((color & 255) == 255) { + + /* + * No alpha-blending required + */ + + /* + * Setup color + */ + colorptr = (Uint8 *) & color; + if (SDL_BYTEORDER == SDL_BIG_ENDIAN) { + color = SDL_MapRGBA(dst->format, colorptr[0], colorptr[1], colorptr[2], colorptr[3]); + } else { + color = SDL_MapRGBA(dst->format, colorptr[3], colorptr[2], colorptr[1], colorptr[0]); + } + + /* + * Lock the surface + */ + if (SDL_MUSTLOCK(dst)) { + if (SDL_LockSurface(dst) < 0) { + return (-1); + } + } + + /* + * More variable setup + */ + pixx = dst->format->BytesPerPixel; + pixy = dst->pitch; + pixel = ((Uint8 *) dst->pixels) + pixx * (int) x1 + pixy * (int) y; + + /* + * Draw + */ + switch (dst->format->BytesPerPixel) { + case 1: + memset(pixel, color, dx + 1); + break; + case 2: + pixellast = pixel + dx + dx; + for (; pixel <= pixellast; pixel += pixx) { + *(Uint16 *) pixel = color; + } + break; + case 3: + pixellast = pixel + dx + dx + dx; + if (SDL_BYTEORDER == SDL_BIG_ENDIAN) { + color3[0] = (color >> 16) & 0xff; + color3[1] = (color >> 8) & 0xff; + color3[2] = color & 0xff; + } else { + color3[0] = color & 0xff; + color3[1] = (color >> 8) & 0xff; + color3[2] = (color >> 16) & 0xff; + } + for (; pixel <= pixellast; pixel += pixx) { + memcpy(pixel, color3, 3); + } + break; + default: /* case 4 */ + dx = dx + dx; + pixellast = pixel + dx + dx; + for (; pixel <= pixellast; pixel += pixx) { + *(Uint32 *) pixel = color; + } + break; + } + + /* + * Unlock surface + */ + if (SDL_MUSTLOCK(dst)) { + SDL_UnlockSurface(dst); + } + + /* + * Set result code + */ + result = 0; + + } else { + + /* + * Alpha blending blit + */ + result = _HLineAlpha(dst, x1, x1 + dx, y, color); + } + + return (result); +} + +/*! +\brief Draw horizontal line with blending. + +\param dst The surface to draw on. +\param x1 X coordinate of the first point (i.e. left) of the line. +\param x2 X coordinate of the second point (i.e. right) of the line. +\param y Y coordinate of the points of the line. +\param r The red value of the line to draw. +\param g The green value of the line to draw. +\param b The blue value of the line to draw. +\param a The alpha value of the line to draw. + +\returns Returns 0 on success, -1 on failure. +*/ +int hlineRGBA(SDL_Surface * dst, Sint16 x1, Sint16 x2, Sint16 y, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + /* + * Draw + */ + return (hlineColor(dst, x1, x2, y, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a)); +} + +/*! +\brief Draw vertical line with blending. + +\param dst The surface to draw on. +\param x X coordinate of the points of the line. +\param y1 Y coordinate of the first point (i.e. top) of the line. +\param y2 Y coordinate of the second point (i.e. bottom) of the line. +\param color The color value of the line to draw (0xRRGGBBAA). + +\returns Returns 0 on success, -1 on failure. +*/ +int vlineColor(SDL_Surface * dst, Sint16 x, Sint16 y1, Sint16 y2, Uint32 color) +{ + Sint16 left, right, top, bottom; + Uint8 *pixel, *pixellast; + int dy; + int pixx, pixy; + Sint16 h; + Sint16 ytmp; + int result = -1; + Uint8 *colorptr; + + /* + * Check visibility of clipping rectangle + */ + if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) { + return(0); + } + + /* + * Swap y1, y2 if required to ensure y1<=y2 + */ + if (y1 > y2) { + ytmp = y1; + y1 = y2; + y2 = ytmp; + } + + /* + * Get clipping boundary and + * check visibility of vline + */ + left = dst->clip_rect.x; + right = dst->clip_rect.x + dst->clip_rect.w - 1; + if ((xright)) { + return (0); + } + top = dst->clip_rect.y; + if (y2clip_rect.y + dst->clip_rect.h - 1; + if (y1>bottom) { + return(0); + } + + /* + * Clip x + */ + if (y1 < top) { + y1 = top; + } + if (y2 > bottom) { + y2 = bottom; + } + + /* + * Calculate height + */ + h = y2 - y1; + + /* + * Alpha check + */ + if ((color & 255) == 255) { + + /* + * No alpha-blending required + */ + + /* + * Setup color + */ + colorptr = (Uint8 *) & color; + if (SDL_BYTEORDER == SDL_BIG_ENDIAN) { + color = SDL_MapRGBA(dst->format, colorptr[0], colorptr[1], colorptr[2], colorptr[3]); + } else { + color = SDL_MapRGBA(dst->format, colorptr[3], colorptr[2], colorptr[1], colorptr[0]); + } + + /* + * Lock the surface + */ + if (SDL_MUSTLOCK(dst)) { + if (SDL_LockSurface(dst) < 0) { + return (-1); + } + } + + /* + * More variable setup + */ + dy = h; + pixx = dst->format->BytesPerPixel; + pixy = dst->pitch; + pixel = ((Uint8 *) dst->pixels) + pixx * (int) x + pixy * (int) y1; + pixellast = pixel + pixy * dy; + + /* + * Draw + */ + switch (dst->format->BytesPerPixel) { + case 1: + for (; pixel <= pixellast; pixel += pixy) { + *(Uint8 *) pixel = color; + } + break; + case 2: + for (; pixel <= pixellast; pixel += pixy) { + *(Uint16 *) pixel = color; + } + break; + case 3: + for (; pixel <= pixellast; pixel += pixy) { + if (SDL_BYTEORDER == SDL_BIG_ENDIAN) { + pixel[0] = (color >> 16) & 0xff; + pixel[1] = (color >> 8) & 0xff; + pixel[2] = color & 0xff; + } else { + pixel[0] = color & 0xff; + pixel[1] = (color >> 8) & 0xff; + pixel[2] = (color >> 16) & 0xff; + } + } + break; + default: /* case 4 */ + for (; pixel <= pixellast; pixel += pixy) { + *(Uint32 *) pixel = color; + } + break; + } + + /* Unlock surface */ + if (SDL_MUSTLOCK(dst)) { + SDL_UnlockSurface(dst); + } + + /* + * Set result code + */ + result = 0; + + } else { + + /* + * Alpha blending blit + */ + + result = _VLineAlpha(dst, x, y1, y1 + h, color); + + } + + return (result); +} + +/*! +\brief Draw vertical line with blending. + +\param dst The surface to draw on. +\param x X coordinate of the points of the line. +\param y1 Y coordinate of the first point (i.e. top) of the line. +\param y2 Y coordinate of the second point (i.e. bottom) of the line. +\param r The red value of the line to draw. +\param g The green value of the line to draw. +\param b The blue value of the line to draw. +\param a The alpha value of the line to draw. + +\returns Returns 0 on success, -1 on failure. +*/ +int vlineRGBA(SDL_Surface * dst, Sint16 x, Sint16 y1, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + /* + * Draw + */ + return (vlineColor(dst, x, y1, y2, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a)); +} + +/*! +\brief Draw rectangle with blending. + +\param dst The surface to draw on. +\param x1 X coordinate of the first point (i.e. top right) of the rectangle. +\param y1 Y coordinate of the first point (i.e. top right) of the rectangle. +\param x2 X coordinate of the second point (i.e. bottom left) of the rectangle. +\param y2 Y coordinate of the second point (i.e. bottom left) of the rectangle. +\param color The color value of the rectangle to draw (0xRRGGBBAA). + +\returns Returns 0 on success, -1 on failure. +*/ +int rectangleColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color) +{ + int result; + Sint16 tmp; + + /* Check destination surface */ + if (dst == NULL) + { + return -1; + } + + /* + * Check visibility of clipping rectangle + */ + if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) { + return 0; + } + + /* + * Test for special cases of straight lines or single point + */ + if (x1 == x2) { + if (y1 == y2) { + return (pixelColor(dst, x1, y1, color)); + } else { + return (vlineColor(dst, x1, y1, y2, color)); + } + } else { + if (y1 == y2) { + return (hlineColor(dst, x1, x2, y1, color)); + } + } + + /* + * Swap x1, x2 if required + */ + if (x1 > x2) { + tmp = x1; + x1 = x2; + x2 = tmp; + } + + /* + * Swap y1, y2 if required + */ + if (y1 > y2) { + tmp = y1; + y1 = y2; + y2 = tmp; + } + + /* + * Draw rectangle + */ + result = 0; + result |= hlineColor(dst, x1, x2, y1, color); + result |= hlineColor(dst, x1, x2, y2, color); + y1 += 1; + y2 -= 1; + if (y1 <= y2) { + result |= vlineColor(dst, x1, y1, y2, color); + result |= vlineColor(dst, x2, y1, y2, color); + } + + return (result); + +} + +/*! +\brief Draw rectangle with blending. + +\param dst The surface to draw on. +\param x1 X coordinate of the first point (i.e. top right) of the rectangle. +\param y1 Y coordinate of the first point (i.e. top right) of the rectangle. +\param x2 X coordinate of the second point (i.e. bottom left) of the rectangle. +\param y2 Y coordinate of the second point (i.e. bottom left) of the rectangle. +\param r The red value of the rectangle to draw. +\param g The green value of the rectangle to draw. +\param b The blue value of the rectangle to draw. +\param a The alpha value of the rectangle to draw. + +\returns Returns 0 on success, -1 on failure. +*/ +int rectangleRGBA(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + /* + * Draw + */ + return (rectangleColor + (dst, x1, y1, x2, y2, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a)); +} + +/*! +\brief Draw rounded-corner rectangle with blending. + +\param dst The surface to draw on. +\param x1 X coordinate of the first point (i.e. top right) of the rectangle. +\param y1 Y coordinate of the first point (i.e. top right) of the rectangle. +\param x2 X coordinate of the second point (i.e. bottom left) of the rectangle. +\param y2 Y coordinate of the second point (i.e. bottom left) of the rectangle. +\param rad The radius of the corner arc. +\param color The color value of the rectangle to draw (0xRRGGBBAA). + +\returns Returns 0 on success, -1 on failure. +*/ +int roundedRectangleColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 rad, Uint32 color) +{ + int result; + Sint16 w, h, tmp; + Sint16 xx1, xx2, yy1, yy2; + + /* + * Check destination surface + */ + if (dst == NULL) + { + return -1; + } + + /* + * Check radius vor valid range + */ + if (rad < 0) { + return -1; + } + + /* + * Special case - no rounding + */ + if (rad == 0) { + return rectangleColor(dst, x1, y1, x2, y2, color); + } + + /* + * Check visibility of clipping rectangle + */ + if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) { + return 0; + } + + /* + * Test for special cases of straight lines or single point + */ + if (x1 == x2) { + if (y1 == y2) { + return (pixelColor(dst, x1, y1, color)); + } else { + return (vlineColor(dst, x1, y1, y2, color)); + } + } else { + if (y1 == y2) { + return (hlineColor(dst, x1, x2, y1, color)); + } + } + + /* + * Swap x1, x2 if required + */ + if (x1 > x2) { + tmp = x1; + x1 = x2; + x2 = tmp; + } + + /* + * Swap y1, y2 if required + */ + if (y1 > y2) { + tmp = y1; + y1 = y2; + y2 = tmp; + } + + /* + * Calculate width&height + */ + w = x2 - x1; + h = y2 - y1; + + /* + * Maybe adjust radius + */ + if ((rad * 2) > w) + { + rad = w / 2; + } + if ((rad * 2) > h) + { + rad = h / 2; + } + + /* + * Draw corners + */ + result = 0; + xx1 = x1 + rad; + xx2 = x2 - rad; + yy1 = y1 + rad; + yy2 = y2 - rad; + result |= arcColor(dst, xx1, yy1, rad, 180, 270, color); + result |= arcColor(dst, xx2, yy1, rad, 270, 360, color); + result |= arcColor(dst, xx1, yy2, rad, 90, 180, color); + result |= arcColor(dst, xx2, yy2, rad, 0, 90, color); + + /* + * Draw lines + */ + if (xx1 <= xx2) { + result |= hlineColor(dst, xx1, xx2, y1, color); + result |= hlineColor(dst, xx1, xx2, y2, color); + } + if (yy1 <= yy2) { + result |= vlineColor(dst, x1, yy1, yy2, color); + result |= vlineColor(dst, x2, yy1, yy2, color); + } + + return result; +} + +/*! +\brief Draw rounded-corner rectangle with blending. + +\param dst The surface to draw on. +\param x1 X coordinate of the first point (i.e. top right) of the rectangle. +\param y1 Y coordinate of the first point (i.e. top right) of the rectangle. +\param x2 X coordinate of the second point (i.e. bottom left) of the rectangle. +\param y2 Y coordinate of the second point (i.e. bottom left) of the rectangle. +\param rad The radius of the corner arc. +\param r The red value of the rectangle to draw. +\param g The green value of the rectangle to draw. +\param b The blue value of the rectangle to draw. +\param a The alpha value of the rectangle to draw. + +\returns Returns 0 on success, -1 on failure. +*/ +int roundedRectangleRGBA(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 rad, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + /* + * Draw + */ + return (roundedRectangleColor + (dst, x1, y1, x2, y2, rad, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a)); +} + +/*! +\brief Draw rounded-corner box (filled rectangle) with blending. + +\param dst The surface to draw on. +\param x1 X coordinate of the first point (i.e. top right) of the box. +\param y1 Y coordinate of the first point (i.e. top right) of the box. +\param x2 X coordinate of the second point (i.e. bottom left) of the box. +\param y2 Y coordinate of the second point (i.e. bottom left) of the box. +\param rad The radius of the corner arcs of the box. +\param color The color value of the box to draw (0xRRGGBBAA). + +\returns Returns 0 on success, -1 on failure. +*/ +int roundedBoxColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 rad, Uint32 color) +{ + int result; + Sint16 w, h, tmp; + Sint16 xx1, xx2, yy1, yy2; + + /* + * Check destination surface + */ + if (dst == NULL) + { + return -1; + } + + /* + * Check radius vor valid range + */ + if (rad < 0) { + return -1; + } + + /* + * Special case - no rounding + */ + if (rad == 0) { + return rectangleColor(dst, x1, y1, x2, y2, color); + } + + /* + * Check visibility of clipping rectangle + */ + if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) { + return 0; + } + + /* + * Test for special cases of straight lines or single point + */ + if (x1 == x2) { + if (y1 == y2) { + return (pixelColor(dst, x1, y1, color)); + } else { + return (vlineColor(dst, x1, y1, y2, color)); + } + } else { + if (y1 == y2) { + return (hlineColor(dst, x1, x2, y1, color)); + } + } + + /* + * Swap x1, x2 if required + */ + if (x1 > x2) { + tmp = x1; + x1 = x2; + x2 = tmp; + } + + /* + * Swap y1, y2 if required + */ + if (y1 > y2) { + tmp = y1; + y1 = y2; + y2 = tmp; + } + + /* + * Calculate width&height + */ + w = x2 - x1; + h = y2 - y1; + + /* + * Maybe adjust radius + */ + if ((rad * 2) > w) + { + rad = w / 2; + } + if ((rad * 2) > h) + { + rad = h / 2; + } + + /* + * Draw corners + */ + result = 0; + xx1 = x1 + rad; + xx2 = x2 - rad; + yy1 = y1 + rad; + yy2 = y2 - rad; + result |= filledPieColor(dst, xx1, yy1, rad, 180, 270, color); + result |= filledPieColor(dst, xx2, yy1, rad, 270, 360, color); + result |= filledPieColor(dst, xx1, yy2, rad, 90, 180, color); + result |= filledPieColor(dst, xx2, yy2, rad, 0, 90, color); + + /* + * Draw body + */ + xx1++; + xx2--; + yy1++; + yy2--; + if (xx1 <= xx2) { + result |= boxColor(dst, xx1, y1, xx2, y2, color); + } + if (yy1 <= yy2) { + result |= boxColor(dst, x1, yy1, xx1-1, yy2, color); + result |= boxColor(dst, xx2+1, yy1, x2, yy2, color); + } + + return result; +} + +/*! +\brief Draw rounded-corner box (filled rectangle) with blending. + +\param dst The surface to draw on. +\param x1 X coordinate of the first point (i.e. top right) of the box. +\param y1 Y coordinate of the first point (i.e. top right) of the box. +\param x2 X coordinate of the second point (i.e. bottom left) of the box. +\param y2 Y coordinate of the second point (i.e. bottom left) of the box. +\param rad The radius of the corner arcs of the box. +\param r The red value of the box to draw. +\param g The green value of the box to draw. +\param b The blue value of the box to draw. +\param a The alpha value of the box to draw. + +\returns Returns 0 on success, -1 on failure. +*/ +int roundedBoxRGBA(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, + Sint16 y2, Sint16 rad, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + /* + * Draw + */ + return (roundedBoxColor + (dst, x1, y1, x2, y2, rad, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a)); +} + +/* --------- Clipping routines for line */ + +/* Clipping based heavily on code from */ +/* http://www.ncsa.uiuc.edu/Vis/Graphics/src/clipCohSuth.c */ + +#define CLIP_LEFT_EDGE 0x1 +#define CLIP_RIGHT_EDGE 0x2 +#define CLIP_BOTTOM_EDGE 0x4 +#define CLIP_TOP_EDGE 0x8 +#define CLIP_INSIDE(a) (!a) +#define CLIP_REJECT(a,b) (a&b) +#define CLIP_ACCEPT(a,b) (!(a|b)) + +/*! +\brief Internal clip-encoding routine. + +Calculates a segement-based clipping encoding for a point against a rectangle. + +\param x X coordinate of point. +\param y Y coordinate of point. +\param left X coordinate of left edge of the rectangle. +\param top Y coordinate of top edge of the rectangle. +\param right X coordinate of right edge of the rectangle. +\param bottom Y coordinate of bottom edge of the rectangle. +*/ +static int _clipEncode(Sint16 x, Sint16 y, Sint16 left, Sint16 top, Sint16 right, Sint16 bottom) +{ + int code = 0; + + if (x < left) { + code |= CLIP_LEFT_EDGE; + } else if (x > right) { + code |= CLIP_RIGHT_EDGE; + } + if (y < top) { + code |= CLIP_TOP_EDGE; + } else if (y > bottom) { + code |= CLIP_BOTTOM_EDGE; + } + return code; +} + +/*! +\brief Clip line to a the clipping rectangle of a surface. + +\param dst Target surface to draw on. +\param x1 Pointer to X coordinate of first point of line. +\param y1 Pointer to Y coordinate of first point of line. +\param x2 Pointer to X coordinate of second point of line. +\param y2 Pointer to Y coordinate of second point of line. +*/ +static int _clipLine(SDL_Surface * dst, Sint16 * x1, Sint16 * y1, Sint16 * x2, Sint16 * y2) +{ + Sint16 left, right, top, bottom; + int code1, code2; + int draw = 0; + Sint16 swaptmp; + float m; + + /* + * Get clipping boundary + */ + left = dst->clip_rect.x; + right = dst->clip_rect.x + dst->clip_rect.w - 1; + top = dst->clip_rect.y; + bottom = dst->clip_rect.y + dst->clip_rect.h - 1; + + while (1) { + code1 = _clipEncode(*x1, *y1, left, top, right, bottom); + code2 = _clipEncode(*x2, *y2, left, top, right, bottom); + if (CLIP_ACCEPT(code1, code2)) { + draw = 1; + break; + } else if (CLIP_REJECT(code1, code2)) + break; + else { + if (CLIP_INSIDE(code1)) { + swaptmp = *x2; + *x2 = *x1; + *x1 = swaptmp; + swaptmp = *y2; + *y2 = *y1; + *y1 = swaptmp; + swaptmp = code2; + code2 = code1; + code1 = swaptmp; + } + if (*x2 != *x1) { + m = (*y2 - *y1) / (float) (*x2 - *x1); + } else { + m = 1.0f; + } + if (code1 & CLIP_LEFT_EDGE) { + *y1 += (Sint16) ((left - *x1) * m); + *x1 = left; + } else if (code1 & CLIP_RIGHT_EDGE) { + *y1 += (Sint16) ((right - *x1) * m); + *x1 = right; + } else if (code1 & CLIP_BOTTOM_EDGE) { + if (*x2 != *x1) { + *x1 += (Sint16) ((bottom - *y1) / m); + } + *y1 = bottom; + } else if (code1 & CLIP_TOP_EDGE) { + if (*x2 != *x1) { + *x1 += (Sint16) ((top - *y1) / m); + } + *y1 = top; + } + } + } + + return draw; +} + +/*! +\brief Draw box (filled rectangle) with blending. + +\param dst The surface to draw on. +\param x1 X coordinate of the first point (i.e. top right) of the box. +\param y1 Y coordinate of the first point (i.e. top right) of the box. +\param x2 X coordinate of the second point (i.e. bottom left) of the box. +\param y2 Y coordinate of the second point (i.e. bottom left) of the box. +\param color The color value of the box to draw (0xRRGGBBAA). + +\returns Returns 0 on success, -1 on failure. +*/ +int boxColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color) +{ + Sint16 left, right, top, bottom; + Uint8 *pixel, *pixellast; + int x, dx; + int dy; + int pixx, pixy; + Sint16 w, h, tmp; + int result; + Uint8 *colorptr; + + /* + * Check visibility of clipping rectangle + */ + if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) { + return(0); + } + + /* + * Order coordinates to ensure that + * x1<=x2 and y1<=y2 + */ + if (x1 > x2) { + tmp = x1; + x1 = x2; + x2 = tmp; + } + if (y1 > y2) { + tmp = y1; + y1 = y2; + y2 = tmp; + } + + /* + * Get clipping boundary and + * check visibility + */ + left = dst->clip_rect.x; + if (x2clip_rect.x + dst->clip_rect.w - 1; + if (x1>right) { + return(0); + } + top = dst->clip_rect.y; + if (y2clip_rect.y + dst->clip_rect.h - 1; + if (y1>bottom) { + return(0); + } + + /* Clip all points */ + if (x1right) { + x1=right; + } + if (x2right) { + x2=right; + } + if (y1bottom) { + y1=bottom; + } + if (y2bottom) { + y2=bottom; + } + + /* + * Test for special cases of straight line or single point + */ + if (x1 == x2) { + if (y1 == y2) { + return (pixelColor(dst, x1, y1, color)); + } else { + return (vlineColor(dst, x1, y1, y2, color)); + } + } + if (y1 == y2) { + return (hlineColor(dst, x1, x2, y1, color)); + } + + /* + * Calculate width&height + */ + w = x2 - x1; + h = y2 - y1; + + /* + * Alpha check + */ + if ((color & 255) == 255) { + + /* + * No alpha-blending required + */ + + /* + * Setup color + */ + colorptr = (Uint8 *) & color; + if (SDL_BYTEORDER == SDL_BIG_ENDIAN) { + color = SDL_MapRGBA(dst->format, colorptr[0], colorptr[1], colorptr[2], colorptr[3]); + } else { + color = SDL_MapRGBA(dst->format, colorptr[3], colorptr[2], colorptr[1], colorptr[0]); + } + + /* + * Lock the surface + */ + if (SDL_MUSTLOCK(dst)) { + if (SDL_LockSurface(dst) < 0) { + return (-1); + } + } + + /* + * More variable setup + */ + dx = w; + dy = h; + pixx = dst->format->BytesPerPixel; + pixy = dst->pitch; + pixel = ((Uint8 *) dst->pixels) + pixx * (int) x1 + pixy * (int) y1; + pixellast = pixel + pixx * dx + pixy * dy; + dx++; + + /* + * Draw + */ + switch (dst->format->BytesPerPixel) { + case 1: + for (; pixel <= pixellast; pixel += pixy) { + memset(pixel, (Uint8) color, dx); + } + break; + case 2: + pixy -= (pixx * dx); + for (; pixel <= pixellast; pixel += pixy) { + for (x = 0; x < dx; x++) { + *(Uint16*) pixel = color; + pixel += pixx; + } + } + break; + case 3: + pixy -= (pixx * dx); + for (; pixel <= pixellast; pixel += pixy) { + for (x = 0; x < dx; x++) { + if (SDL_BYTEORDER == SDL_BIG_ENDIAN) { + pixel[0] = (color >> 16) & 0xff; + pixel[1] = (color >> 8) & 0xff; + pixel[2] = color & 0xff; + } else { + pixel[0] = color & 0xff; + pixel[1] = (color >> 8) & 0xff; + pixel[2] = (color >> 16) & 0xff; + } + pixel += pixx; + } + } + break; + default: /* case 4 */ + pixy -= (pixx * dx); + for (; pixel <= pixellast; pixel += pixy) { + for (x = 0; x < dx; x++) { + *(Uint32 *) pixel = color; + pixel += pixx; + } + } + break; + } + + /* Unlock surface */ + if (SDL_MUSTLOCK(dst)) { + SDL_UnlockSurface(dst); + } + + result = 0; + + } else { + + result = filledRectAlpha(dst, x1, y1, x1 + w, y1 + h, color); + + } + + return (result); +} + +/*! +\brief Draw box (filled rectangle) with blending. + +\param dst The surface to draw on. +\param x1 X coordinate of the first point (i.e. top right) of the box. +\param y1 Y coordinate of the first point (i.e. top right) of the box. +\param x2 X coordinate of the second point (i.e. bottom left) of the box. +\param y2 Y coordinate of the second point (i.e. bottom left) of the box. +\param r The red value of the box to draw. +\param g The green value of the box to draw. +\param b The blue value of the box to draw. +\param a The alpha value of the box to draw. + +\returns Returns 0 on success, -1 on failure. +*/ +int boxRGBA(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + /* + * Draw + */ + return (boxColor(dst, x1, y1, x2, y2, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a)); +} + +/* ----- Line */ + +/* Non-alpha line drawing code adapted from routine */ +/* by Pete Shinners, pete@shinners.org */ +/* Originally from pygame, http://pygame.seul.org */ + +#define ABS(a) (((a)<0) ? -(a) : (a)) + +/*! +\brief Draw line with alpha blending. + +\param dst The surface to draw on. +\param x1 X coordinate of the first point of the line. +\param y1 Y coordinate of the first point of the line. +\param x2 X coordinate of the second point of the line. +\param y2 Y coordinate of the second point of the line. +\param color The color value of the line to draw (0xRRGGBBAA). + +\returns Returns 0 on success, -1 on failure. +*/ +int lineColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color) +{ + int pixx, pixy; + int x, y; + int dx, dy; + int ax, ay; + int sx, sy; + int swaptmp; + Uint8 *pixel; + Uint8 *colorptr; + + /* + * Clip line and test if we have to draw + */ + if (!(_clipLine(dst, &x1, &y1, &x2, &y2))) { + return (0); + } + + /* + * Test for special cases of straight lines or single point + */ + if (x1 == x2) { + if (y1 < y2) { + return (vlineColor(dst, x1, y1, y2, color)); + } else if (y1 > y2) { + return (vlineColor(dst, x1, y2, y1, color)); + } else { + return (pixelColor(dst, x1, y1, color)); + } + } + if (y1 == y2) { + if (x1 < x2) { + return (hlineColor(dst, x1, x2, y1, color)); + } else if (x1 > x2) { + return (hlineColor(dst, x2, x1, y1, color)); + } + } + + /* + * Variable setup + */ + dx = x2 - x1; + dy = y2 - y1; + sx = (dx >= 0) ? 1 : -1; + sy = (dy >= 0) ? 1 : -1; + + /* Lock surface */ + if (SDL_MUSTLOCK(dst)) { + if (SDL_LockSurface(dst) < 0) { + return (-1); + } + } + + /* + * Check for alpha blending + */ + if ((color & 255) == 255) { + + /* + * No alpha blending - use fast pixel routines + */ + + /* + * Setup color + */ + colorptr = (Uint8 *) & color; + if (SDL_BYTEORDER == SDL_BIG_ENDIAN) { + color = SDL_MapRGBA(dst->format, colorptr[0], colorptr[1], colorptr[2], colorptr[3]); + } else { + color = SDL_MapRGBA(dst->format, colorptr[3], colorptr[2], colorptr[1], colorptr[0]); + } + + /* + * More variable setup + */ + dx = sx * dx + 1; + dy = sy * dy + 1; + pixx = dst->format->BytesPerPixel; + pixy = dst->pitch; + pixel = ((Uint8 *) dst->pixels) + pixx * (int) x1 + pixy * (int) y1; + pixx *= sx; + pixy *= sy; + if (dx < dy) { + swaptmp = dx; + dx = dy; + dy = swaptmp; + swaptmp = pixx; + pixx = pixy; + pixy = swaptmp; + } + + /* + * Draw + */ + x = 0; + y = 0; + switch (dst->format->BytesPerPixel) { + case 1: + for (; x < dx; x++, pixel += pixx) { + *pixel = color; + y += dy; + if (y >= dx) { + y -= dx; + pixel += pixy; + } + } + break; + case 2: + for (; x < dx; x++, pixel += pixx) { + *(Uint16 *) pixel = color; + y += dy; + if (y >= dx) { + y -= dx; + pixel += pixy; + } + } + break; + case 3: + for (; x < dx; x++, pixel += pixx) { + if (SDL_BYTEORDER == SDL_BIG_ENDIAN) { + pixel[0] = (color >> 16) & 0xff; + pixel[1] = (color >> 8) & 0xff; + pixel[2] = color & 0xff; + } else { + pixel[0] = color & 0xff; + pixel[1] = (color >> 8) & 0xff; + pixel[2] = (color >> 16) & 0xff; + } + y += dy; + if (y >= dx) { + y -= dx; + pixel += pixy; + } + } + break; + default: /* case 4 */ + for (; x < dx; x++, pixel += pixx) { + *(Uint32 *) pixel = color; + y += dy; + if (y >= dx) { + y -= dx; + pixel += pixy; + } + } + break; + } + + } else { + + /* + * Alpha blending required - use single-pixel blits + */ + + ax = ABS(dx) << 1; + ay = ABS(dy) << 1; + x = x1; + y = y1; + if (ax > ay) { + int d = ay - (ax >> 1); + + while (x != x2) { + pixelColorNolock (dst, x, y, color); + if (d > 0 || (d == 0 && sx == 1)) { + y += sy; + d -= ax; + } + x += sx; + d += ay; + } + } else { + int d = ax - (ay >> 1); + + while (y != y2) { + pixelColorNolock (dst, x, y, color); + if (d > 0 || ((d == 0) && (sy == 1))) { + x += sx; + d -= ay; + } + y += sy; + d += ax; + } + } + pixelColorNolock (dst, x, y, color); + + } + + /* Unlock surface */ + if (SDL_MUSTLOCK(dst)) { + SDL_UnlockSurface(dst); + } + + return (0); +} + +/*! +\brief Draw line with alpha blending. + +\param dst The surface to draw on. +\param x1 X coordinate of the first point of the line. +\param y1 Y coordinate of the first point of the line. +\param x2 X coordinate of the second point of the line. +\param y2 Y coordinate of the second point of the line. +\param r The red value of the line to draw. +\param g The green value of the line to draw. +\param b The blue value of the line to draw. +\param a The alpha value of the line to draw. + +\returns Returns 0 on success, -1 on failure. +*/ +int lineRGBA(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + /* + * Draw + */ + return (lineColor(dst, x1, y1, x2, y2, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a)); +} + +/* AA Line */ + +#define AAlevels 256 +#define AAbits 8 + +/*! +\brief Internal function to draw anti-aliased line with alpha blending and endpoint control. + +This implementation of the Wu antialiasing code is based on Mike Abrash's +DDJ article which was reprinted as Chapter 42 of his Graphics Programming +Black Book, but has been optimized to work with SDL and utilizes 32-bit +fixed-point arithmetic by A. Schiffler. The endpoint control allows the +supression to draw the last pixel useful for rendering continous aa-lines +with alpha<255. + +\param dst The surface to draw on. +\param x1 X coordinate of the first point of the aa-line. +\param y1 Y coordinate of the first point of the aa-line. +\param x2 X coordinate of the second point of the aa-line. +\param y2 Y coordinate of the second point of the aa-line. +\param color The color value of the aa-line to draw (0xRRGGBBAA). +\param draw_endpoint Flag indicating if the endpoint should be drawn; draw if non-zero. + +\returns Returns 0 on success, -1 on failure. +*/ +int _aalineColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color, int draw_endpoint) +{ + Sint32 xx0, yy0, xx1, yy1; + int result; + Uint32 intshift, erracc, erradj; + Uint32 erracctmp, wgt, wgtcompmask; + int dx, dy, tmp, xdir, y0p1, x0pxdir; + + /* + * Check visibility of clipping rectangle + */ + if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) { + return(0); + } + + /* + * Clip line and test if we have to draw + */ + if (!(_clipLine(dst, &x1, &y1, &x2, &y2))) { + return (0); + } + + /* + * Keep on working with 32bit numbers + */ + xx0 = x1; + yy0 = y1; + xx1 = x2; + yy1 = y2; + + /* + * Reorder points if required + */ + if (yy0 > yy1) { + tmp = yy0; + yy0 = yy1; + yy1 = tmp; + tmp = xx0; + xx0 = xx1; + xx1 = tmp; + } + + /* + * Calculate distance + */ + dx = xx1 - xx0; + dy = yy1 - yy0; + + /* + * Check for special cases + */ + if (dx == 0) { + /* + * Vertical line + */ + if (draw_endpoint) + { + return (vlineColor(dst, x1, y1, y2, color)); + } else { + if (dy>0) { + return (vlineColor(dst, x1, yy0, yy0+dy, color)); + } else { + return (pixelColor(dst, x1, y1, color)); + } + } + } else if (dy == 0) { + /* + * Horizontal line + */ + if (draw_endpoint) + { + return (hlineColor(dst, x1, x2, y1, color)); + } else { + if (dx>0) { + return (hlineColor(dst, xx0, xx0+dx, y1, color)); + } else { + return (pixelColor(dst, x1, y1, color)); + } + } + } else if ((dx == dy) && (draw_endpoint)) { + /* + * Diagonal line (with endpoint) + */ + return (lineColor(dst, x1, y1, x2, y2, color)); + } + + /* + * Adjust for negative dx and set xdir + */ + if (dx >= 0) { + xdir = 1; + } else { + xdir = -1; + dx = (-dx); + } + + /* + * Line is not horizontal, vertical or diagonal (with endpoint) + */ + result = 0; + + /* + * Zero accumulator + */ + erracc = 0; + + /* + * # of bits by which to shift erracc to get intensity level + */ + intshift = 32 - AAbits; + + /* + * Mask used to flip all bits in an intensity weighting + */ + wgtcompmask = AAlevels - 1; + + /* Lock surface */ + if (SDL_MUSTLOCK(dst)) { + if (SDL_LockSurface(dst) < 0) { + return (-1); + } + } + + /* + * Draw the initial pixel in the foreground color + */ + result |= pixelColorNolock(dst, x1, y1, color); + + /* + * x-major or y-major? + */ + if (dy > dx) { + + /* + * y-major. Calculate 16-bit fixed point fractional part of a pixel that + * X advances every time Y advances 1 pixel, truncating the result so that + * we won't overrun the endpoint along the X axis + */ + /* + * Not-so-portable version: erradj = ((Uint64)dx << 32) / (Uint64)dy; + */ + erradj = ((dx << 16) / dy) << 16; + + /* + * draw all pixels other than the first and last + */ + x0pxdir = xx0 + xdir; + while (--dy) { + erracctmp = erracc; + erracc += erradj; + if (erracc <= erracctmp) { + /* + * rollover in error accumulator, x coord advances + */ + xx0 = x0pxdir; + x0pxdir += xdir; + } + yy0++; /* y-major so always advance Y */ + + /* + * the AAbits most significant bits of erracc give us the intensity + * weighting for this pixel, and the complement of the weighting for + * the paired pixel. + */ + wgt = (erracc >> intshift) & 255; + result |= pixelColorWeightNolock (dst, xx0, yy0, color, 255 - wgt); + result |= pixelColorWeightNolock (dst, x0pxdir, yy0, color, wgt); + } + + } else { + + /* + * x-major line. Calculate 16-bit fixed-point fractional part of a pixel + * that Y advances each time X advances 1 pixel, truncating the result so + * that we won't overrun the endpoint along the X axis. + */ + /* + * Not-so-portable version: erradj = ((Uint64)dy << 32) / (Uint64)dx; + */ + erradj = ((dy << 16) / dx) << 16; + + /* + * draw all pixels other than the first and last + */ + y0p1 = yy0 + 1; + while (--dx) { + + erracctmp = erracc; + erracc += erradj; + if (erracc <= erracctmp) { + /* + * Accumulator turned over, advance y + */ + yy0 = y0p1; + y0p1++; + } + xx0 += xdir; /* x-major so always advance X */ + /* + * the AAbits most significant bits of erracc give us the intensity + * weighting for this pixel, and the complement of the weighting for + * the paired pixel. + */ + wgt = (erracc >> intshift) & 255; + result |= pixelColorWeightNolock (dst, xx0, yy0, color, 255 - wgt); + result |= pixelColorWeightNolock (dst, xx0, y0p1, color, wgt); + } + } + + /* + * Do we have to draw the endpoint + */ + if (draw_endpoint) { + /* + * Draw final pixel, always exactly intersected by the line and doesn't + * need to be weighted. + */ + result |= pixelColorNolock (dst, x2, y2, color); + } + + /* Unlock surface */ + if (SDL_MUSTLOCK(dst)) { + SDL_UnlockSurface(dst); + } + + return (result); +} + +/*! +\brief Ddraw anti-aliased line with alpha blending. + +\param dst The surface to draw on. +\param x1 X coordinate of the first point of the aa-line. +\param y1 Y coordinate of the first point of the aa-line. +\param x2 X coordinate of the second point of the aa-line. +\param y2 Y coordinate of the second point of the aa-line. +\param color The color value of the aa-line to draw (0xRRGGBBAA). + +\returns Returns 0 on success, -1 on failure. +*/ +int aalineColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color) +{ + return (_aalineColor(dst, x1, y1, x2, y2, color, 1)); +} + +/*! +\brief Draw anti-aliased line with alpha blending. + +\param dst The surface to draw on. +\param x1 X coordinate of the first point of the aa-line. +\param y1 Y coordinate of the first point of the aa-line. +\param x2 X coordinate of the second point of the aa-line. +\param y2 Y coordinate of the second point of the aa-line. +\param r The red value of the aa-line to draw. +\param g The green value of the aa-line to draw. +\param b The blue value of the aa-line to draw. +\param a The alpha value of the aa-line to draw. + +\returns Returns 0 on success, -1 on failure. +*/ +int aalineRGBA(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + return (_aalineColor + (dst, x1, y1, x2, y2, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a, 1)); +} + + +/* ----- Circle */ + +/*! +\brief Draw circle with blending. + +Note: Circle drawing routine is based on an algorithms from the sge library, +but modified by A. Schiffler for multiple pixel-draw removal and other +minor speedup changes. + +\param dst The surface to draw on. +\param x X coordinate of the center of the circle. +\param y Y coordinate of the center of the circle. +\param rad Radius in pixels of the circle. +\param color The color value of the circle to draw (0xRRGGBBAA). + +\returns Returns 0 on success, -1 on failure. +*/ +int circleColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad, Uint32 color) +{ + Sint16 left, right, top, bottom; + int result; + Sint16 x1, y1, x2, y2; + Sint16 cx = 0; + Sint16 cy = rad; + Sint16 ocx = (Sint16) 0xffff; + Sint16 ocy = (Sint16) 0xffff; + Sint16 df = 1 - rad; + Sint16 d_e = 3; + Sint16 d_se = -2 * rad + 5; + Sint16 xpcx, xmcx, xpcy, xmcy; + Sint16 ypcy, ymcy, ypcx, ymcx; + Uint8 *colorptr; + + /* + * Check visibility of clipping rectangle + */ + if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) { + return(0); + } + + /* + * Sanity check radius + */ + if (rad < 0) { + return (-1); + } + + /* + * Special case for rad=0 - draw a point + */ + if (rad == 0) { + return (pixelColor(dst, x, y, color)); + } + + /* + * Get circle and clipping boundary and + * test if bounding box of circle is visible + */ + x2 = x + rad; + left = dst->clip_rect.x; + if (x2clip_rect.x + dst->clip_rect.w - 1; + if (x1>right) { + return(0); + } + y2 = y + rad; + top = dst->clip_rect.y; + if (y2clip_rect.y + dst->clip_rect.h - 1; + if (y1>bottom) { + return(0); + } + + /* + * Draw circle + */ + result = 0; + + /* Lock surface */ + if (SDL_MUSTLOCK(dst)) { + if (SDL_LockSurface(dst) < 0) { + return (-1); + } + } + + /* + * Alpha Check + */ + if ((color & 255) == 255) { + + /* + * No Alpha - direct memory writes + */ + + /* + * Setup color + */ + colorptr = (Uint8 *) & color; + if (SDL_BYTEORDER == SDL_BIG_ENDIAN) { + color = SDL_MapRGBA(dst->format, colorptr[0], colorptr[1], colorptr[2], colorptr[3]); + } else { + color = SDL_MapRGBA(dst->format, colorptr[3], colorptr[2], colorptr[1], colorptr[0]); + } + + /* + * Draw + */ + do { + ypcy = y + cy; + ymcy = y - cy; + if (cx > 0) { + xpcx = x + cx; + xmcx = x - cx; + result |= fastPixelColorNolock(dst, xmcx, ypcy, color); + result |= fastPixelColorNolock(dst, xpcx, ypcy, color); + result |= fastPixelColorNolock(dst, xmcx, ymcy, color); + result |= fastPixelColorNolock(dst, xpcx, ymcy, color); + } else { + result |= fastPixelColorNolock(dst, x, ymcy, color); + result |= fastPixelColorNolock(dst, x, ypcy, color); + } + xpcy = x + cy; + xmcy = x - cy; + if ((cx > 0) && (cx != cy)) { + ypcx = y + cx; + ymcx = y - cx; + result |= fastPixelColorNolock(dst, xmcy, ypcx, color); + result |= fastPixelColorNolock(dst, xpcy, ypcx, color); + result |= fastPixelColorNolock(dst, xmcy, ymcx, color); + result |= fastPixelColorNolock(dst, xpcy, ymcx, color); + } else if (cx == 0) { + result |= fastPixelColorNolock(dst, xmcy, y, color); + result |= fastPixelColorNolock(dst, xpcy, y, color); + } + /* + * Update + */ + if (df < 0) { + df += d_e; + d_e += 2; + d_se += 2; + } else { + df += d_se; + d_e += 2; + d_se += 4; + cy--; + } + cx++; + } while (cx <= cy); + + /* + * Unlock surface + */ + SDL_UnlockSurface(dst); + + } else { + + /* + * Using Alpha - blended pixel blits + */ + + do { + /* + * Draw + */ + ypcy = y + cy; + ymcy = y - cy; + if (cx > 0) { + xpcx = x + cx; + xmcx = x - cx; + result |= pixelColorNolock (dst, xmcx, ypcy, color); + result |= pixelColorNolock (dst, xpcx, ypcy, color); + result |= pixelColorNolock (dst, xmcx, ymcy, color); + result |= pixelColorNolock (dst, xpcx, ymcy, color); + } else { + result |= pixelColorNolock (dst, x, ymcy, color); + result |= pixelColorNolock (dst, x, ypcy, color); + } + xpcy = x + cy; + xmcy = x - cy; + if ((cx > 0) && (cx != cy)) { + ypcx = y + cx; + ymcx = y - cx; + result |= pixelColorNolock (dst, xmcy, ypcx, color); + result |= pixelColorNolock (dst, xpcy, ypcx, color); + result |= pixelColorNolock (dst, xmcy, ymcx, color); + result |= pixelColorNolock (dst, xpcy, ymcx, color); + } else if (cx == 0) { + result |= pixelColorNolock (dst, xmcy, y, color); + result |= pixelColorNolock (dst, xpcy, y, color); + } + /* + * Update + */ + if (df < 0) { + df += d_e; + d_e += 2; + d_se += 2; + } else { + df += d_se; + d_e += 2; + d_se += 4; + cy--; + } + cx++; + } while (cx <= cy); + + } /* Alpha check */ + + /* Unlock surface */ + if (SDL_MUSTLOCK(dst)) { + SDL_UnlockSurface(dst); + } + + return (result); +} + +/*! +\brief Draw circle with blending. + +\param dst The surface to draw on. +\param x X coordinate of the center of the circle. +\param y Y coordinate of the center of the circle. +\param rad Radius in pixels of the circle. +\param r The red value of the circle to draw. +\param g The green value of the circle to draw. +\param b The blue value of the circle to draw. +\param a The alpha value of the circle to draw. + +\returns Returns 0 on success, -1 on failure. +*/ +int circleRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + /* + * Draw + */ + return (circleColor(dst, x, y, rad, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a)); +} + +/* ----- Arc */ + +/*! +\brief Arc with blending. + +Note Arc drawing is based on circle algorithm by A. Schiffler and +written by D. Raber. Calculates which octants arc goes through and +renders pixels accordingly. + +\param dst The surface to draw on. +\param x X coordinate of the center of the arc. +\param y Y coordinate of the center of the arc. +\param rad Radius in pixels of the arc. +\param start Starting radius in degrees of the arc. 0 degrees is down, increasing counterclockwise. +\param end Ending radius in degrees of the arc. 0 degrees is down, increasing counterclockwise. +\param color The color value of the arc to draw (0xRRGGBBAA). + +\returns Returns 0 on success, -1 on failure. +*/ +int arcColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad, Sint16 start, Sint16 end, Uint32 color) +{ + Sint16 left, right, top, bottom; + int result; + Sint16 x1, y1, x2, y2; + Sint16 cx = 0; + Sint16 cy = rad; + Sint16 ocx = (Sint16) 0xffff; + Sint16 ocy = (Sint16) 0xffff; + Sint16 df = 1 - rad; + Sint16 d_e = 3; + Sint16 d_se = -2 * rad + 5; + Sint16 xpcx, xmcx, xpcy, xmcy; + Sint16 ypcy, ymcy, ypcx, ymcx; + Uint8 *colorptr; + Uint8 drawoct; + int startoct, endoct, oct, stopval_start, stopval_end; + double temp; + + /* + * Check visibility of clipping rectangle + */ + if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) { + return(0); + } + + /* + * Sanity check radius + */ + if (rad < 0) { + return (-1); + } + + /* + * Special case for rad=0 - draw a point + */ + if (rad == 0) { + return (pixelColor(dst, x, y, color)); + } + + /* + * Get arc's circle and clipping boundary and + * test if bounding box of circle is visible + */ + x2 = x + rad; + left = dst->clip_rect.x; + if (x2clip_rect.x + dst->clip_rect.w - 1; + if (x1>right) { + return(0); + } + y2 = y + rad; + top = dst->clip_rect.y; + if (y2clip_rect.y + dst->clip_rect.h - 1; + if (y1>bottom) { + return(0); + } + + // Octant labelling + // + // \ 5 | 6 / + // \ | / + // 4 \ | / 7 + // \|/ + //------+------ +x + // /|\ + // 3 / | \ 0 + // / | \ + // / 2 | 1 \ + // +y + + // Initially reset bitmask to 0x00000000 + // the set whether or not to keep drawing a given octant. + // For example: 0x00111100 means we're drawing in octants 2-5 + drawoct = 0; + + /* + * Fixup angles + */ + start %= 360; + end %= 360; + // 0 <= start & end < 360; note that sometimes start > end - if so, arc goes back through 0. + while (start < 0) start += 360; + while (end < 0) end += 360; + start %= 360; + end %= 360; + + // now, we find which octants we're drawing in. + startoct = start / 45; + endoct = end / 45; + oct = startoct - 1; // we increment as first step in loop + + // stopval_start, stopval_end; + // what values of cx to stop at. + do { + oct = (oct + 1) % 8; + + if (oct == startoct) { + // need to compute stopval_start for this octant. Look at picture above if this is unclear + switch (oct) + { + case 0: + case 3: + temp = sin(start * M_PI / 180); + break; + case 1: + case 6: + temp = cos(start * M_PI / 180); + break; + case 2: + case 5: + temp = -cos(start * M_PI / 180); + break; + case 4: + case 7: + temp = -sin(start * M_PI / 180); + break; + } + temp *= rad; + stopval_start = (int)temp; // always round down. + // This isn't arbitrary, but requires graph paper to explain well. + // The basic idea is that we're always changing drawoct after we draw, so we + // stop immediately after we render the last sensible pixel at x = ((int)temp). + + // and whether to draw in this octant initially + if (oct % 2) drawoct |= (1 << oct); // this is basically like saying drawoct[oct] = true, if drawoct were a bool array + else drawoct &= 255 - (1 << oct); // this is basically like saying drawoct[oct] = false + } + if (oct == endoct) { + // need to compute stopval_end for this octant + switch (oct) + { + case 0: + case 3: + temp = sin(end * M_PI / 180); + break; + case 1: + case 6: + temp = cos(end * M_PI / 180); + break; + case 2: + case 5: + temp = -cos(end * M_PI / 180); + break; + case 4: + case 7: + temp = -sin(end * M_PI / 180); + break; + } + temp *= rad; + stopval_end = (int)temp; + + // and whether to draw in this octant initially + if (startoct == endoct) { + // note: we start drawing, stop, then start again in this case + // otherwise: we only draw in this octant, so initialize it to false, it will get set back to true + if (start > end) { + // unfortunately, if we're in the same octant and need to draw over the whole circle, + // we need to set the rest to true, because the while loop will end at the bottom. + drawoct = 255; + } else { + drawoct &= 255 - (1 << oct); + } + } + else if (oct % 2) drawoct &= 255 - (1 << oct); + else drawoct |= (1 << oct); + } else if (oct != startoct) { // already verified that it's != endoct + drawoct |= (1 << oct); // draw this entire segment + } + } while (oct != endoct); + + // so now we have what octants to draw and when to draw them. all that's left is the actual raster code. + + /* Lock surface */ + if (SDL_MUSTLOCK(dst)) { + if (SDL_LockSurface(dst) < 0) { + return (-1); + } + } + + /* + * Draw arc + */ + result = 0; + + /* + * Alpha Check + */ + if ((color & 255) == 255) { + + /* + * No Alpha - direct memory writes + */ + + /* + * Setup color + */ + colorptr = (Uint8 *) & color; + if (SDL_BYTEORDER == SDL_BIG_ENDIAN) { + color = SDL_MapRGBA(dst->format, colorptr[0], colorptr[1], colorptr[2], colorptr[3]); + } else { + color = SDL_MapRGBA(dst->format, colorptr[3], colorptr[2], colorptr[1], colorptr[0]); + } + + /* + * Draw + */ + do { + ypcy = y + cy; + ymcy = y - cy; + if (cx > 0) { + xpcx = x + cx; + xmcx = x - cx; + // always check if we're drawing a certain octant before adding a pixel to that octant. + if (drawoct & 4) result |= fastPixelColorNolock(dst, xmcx, ypcy, color); // drawoct & 4 = 22; drawoct[2] + if (drawoct & 2) result |= fastPixelColorNolock(dst, xpcx, ypcy, color); + if (drawoct & 32) result |= fastPixelColorNolock(dst, xmcx, ymcy, color); + if (drawoct & 64) result |= fastPixelColorNolock(dst, xpcx, ymcy, color); + } else { + if (drawoct & 6) result |= fastPixelColorNolock(dst, x, ypcy, color); // 4 + 2; drawoct[2] || drawoct[1] + if (drawoct & 96) result |= fastPixelColorNolock(dst, x, ymcy, color); // 32 + 64 + } + + xpcy = x + cy; + xmcy = x - cy; + if (cx > 0 && cx != cy) { + ypcx = y + cx; + ymcx = y - cx; + if (drawoct & 8) result |= fastPixelColorNolock(dst, xmcy, ypcx, color); + if (drawoct & 1) result |= fastPixelColorNolock(dst, xpcy, ypcx, color); + if (drawoct & 16) result |= fastPixelColorNolock(dst, xmcy, ymcx, color); + if (drawoct & 128) result |= fastPixelColorNolock(dst, xpcy, ymcx, color); + } else if (cx == 0) { + if (drawoct & 24) result |= fastPixelColorNolock(dst, xmcy, y, color); // 8 + 16 + if (drawoct & 129) result |= fastPixelColorNolock(dst, xpcy, y, color); // 1 + 128 + } + + /* + * Update whether we're drawing an octant + */ + if (stopval_start == cx) { + // works like an on-off switch because start & end may be in the same octant. + if (drawoct & (1 << startoct)) drawoct &= 255 - (1 << startoct); + else drawoct |= (1 << startoct); + } + if (stopval_end == cx) { + if (drawoct & (1 << endoct)) drawoct &= 255 - (1 << endoct); + else drawoct |= (1 << endoct); + } + + /* + * Update pixels + */ + if (df < 0) { + df += d_e; + d_e += 2; + d_se += 2; + } else { + df += d_se; + d_e += 2; + d_se += 4; + cy--; + } + cx++; + } while (cx <= cy); + + /* + * Unlock surface + */ + SDL_UnlockSurface(dst); + + } else { + + /* + * Using Alpha - blended pixel blits + */ + + do { + ypcy = y + cy; + ymcy = y - cy; + if (cx > 0) { + xpcx = x + cx; + xmcx = x - cx; + + // always check if we're drawing a certain octant before adding a pixel to that octant. + if (drawoct & 4) result |= pixelColorNolock(dst, xmcx, ypcy, color); + if (drawoct & 2) result |= pixelColorNolock(dst, xpcx, ypcy, color); + if (drawoct & 32) result |= pixelColorNolock(dst, xmcx, ymcy, color); + if (drawoct & 64) result |= pixelColorNolock(dst, xpcx, ymcy, color); + } else { + if (drawoct & 96) result |= pixelColorNolock(dst, x, ymcy, color); + if (drawoct & 6) result |= pixelColorNolock(dst, x, ypcy, color); + } + + xpcy = x + cy; + xmcy = x - cy; + if (cx > 0 && cx != cy) { + ypcx = y + cx; + ymcx = y - cx; + if (drawoct & 8) result |= pixelColorNolock(dst, xmcy, ypcx, color); + if (drawoct & 1) result |= pixelColorNolock(dst, xpcy, ypcx, color); + if (drawoct & 16) result |= pixelColorNolock(dst, xmcy, ymcx, color); + if (drawoct & 128) result |= pixelColorNolock(dst, xpcy, ymcx, color); + } else if (cx == 0) { + if (drawoct & 24) result |= pixelColorNolock(dst, xmcy, y, color); + if (drawoct & 129) result |= pixelColorNolock(dst, xpcy, y, color); + } + + /* + * Update whether we're drawing an octant + */ + if (stopval_start == cx) { + // works like an on-off switch. + // This is just in case start & end are in the same octant. + if (drawoct & (1 << startoct)) drawoct &= 255 - (1 << startoct); + else drawoct |= (1 << startoct); + } + if (stopval_end == cx) { + if (drawoct & (1 << endoct)) drawoct &= 255 - (1 << endoct); + else drawoct |= (1 << endoct); + } + + /* + * Update pixels + */ + if (df < 0) { + df += d_e; + d_e += 2; + d_se += 2; + } else { + df += d_se; + d_e += 2; + d_se += 4; + cy--; + } + cx++; + } while (cx <= cy); + + } /* Alpha check */ + + /* Unlock surface */ + if (SDL_MUSTLOCK(dst)) { + SDL_UnlockSurface(dst); + } + + return (result); +} + +/*! +\brief Arc with blending. + +\param dst The surface to draw on. +\param x X coordinate of the center of the arc. +\param y Y coordinate of the center of the arc. +\param rad Radius in pixels of the arc. +\param start Starting radius in degrees of the arc. 0 degrees is down, increasing counterclockwise. +\param end Ending radius in degrees of the arc. 0 degrees is down, increasing counterclockwise. +\param r The red value of the arc to draw. +\param g The green value of the arc to draw. +\param b The blue value of the arc to draw. +\param a The alpha value of the arc to draw. + +\returns Returns 0 on success, -1 on failure. +*/ +int arcRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad, Sint16 start, Sint16 end, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + /* + * Draw + */ + return (arcColor(dst, x, y, rad, start, end, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a)); +} + +/* ----- AA Circle */ + + +/*! +\brief Draw anti-aliased circle with blending. + +Note: The AA-circle routine is based on AA-ellipse with identical radii. + +\param dst The surface to draw on. +\param x X coordinate of the center of the aa-circle. +\param y Y coordinate of the center of the aa-circle. +\param rad Radius in pixels of the aa-circle. +\param color The color value of the aa-circle to draw (0xRRGGBBAA). + +\returns Returns 0 on success, -1 on failure. +*/ +int aacircleColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad, Uint32 color) +{ + return (aaellipseColor(dst, x, y, rad, rad, color)); +} + +/*! +\brief Draw anti-aliased circle with blending. + +\param dst The surface to draw on. +\param x X coordinate of the center of the aa-circle. +\param y Y coordinate of the center of the aa-circle. +\param rad Radius in pixels of the aa-circle. +\param r The red value of the aa-circle to draw. +\param g The green value of the aa-circle to draw. +\param b The blue value of the aa-circle to draw. +\param a The alpha value of the aa-circle to draw. + +\returns Returns 0 on success, -1 on failure. +*/ +int aacircleRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + /* + * Draw + */ + return (aaellipseColor + (dst, x, y, rad, rad, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a)); +} + +/* ----- Filled Circle */ + +/*! +\brief Draw filled circle with blending. + +Note: Based on algorithms from sge library with modifications by A. Schiffler for +multiple-hline draw removal and other minor speedup changes. + +\param dst The surface to draw on. +\param x X coordinate of the center of the filled circle. +\param y Y coordinate of the center of the filled circle. +\param rad Radius in pixels of the filled circle. +\param color The color value of the filled circle to draw (0xRRGGBBAA). + +\returns Returns 0 on success, -1 on failure. +*/ +int filledCircleColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad, Uint32 color) +{ + Sint16 left, right, top, bottom; + int result; + Sint16 x1, y1, x2, y2; + Sint16 cx = 0; + Sint16 cy = rad; + Sint16 ocx = (Sint16) 0xffff; + Sint16 ocy = (Sint16) 0xffff; + Sint16 df = 1 - rad; + Sint16 d_e = 3; + Sint16 d_se = -2 * rad + 5; + Sint16 xpcx, xmcx, xpcy, xmcy; + Sint16 ypcy, ymcy, ypcx, ymcx; + + /* + * Check visibility of clipping rectangle + */ + if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) { + return(0); + } + + /* + * Sanity check radius + */ + if (rad < 0) { + return (-1); + } + + /* + * Special case for rad=0 - draw a point + */ + if (rad == 0) { + return (pixelColor(dst, x, y, color)); + } + + /* + * Get circle and clipping boundary and + * test if bounding box of circle is visible + */ + x2 = x + rad; + left = dst->clip_rect.x; + if (x2clip_rect.x + dst->clip_rect.w - 1; + if (x1>right) { + return(0); + } + y2 = y + rad; + top = dst->clip_rect.y; + if (y2clip_rect.y + dst->clip_rect.h - 1; + if (y1>bottom) { + return(0); + } + + /* + * Draw + */ + result = 0; + do { + xpcx = x + cx; + xmcx = x - cx; + xpcy = x + cy; + xmcy = x - cy; + if (ocy != cy) { + if (cy > 0) { + ypcy = y + cy; + ymcy = y - cy; + result |= hlineColor(dst, xmcx, xpcx, ypcy, color); + result |= hlineColor(dst, xmcx, xpcx, ymcy, color); + } else { + result |= hlineColor(dst, xmcx, xpcx, y, color); + } + ocy = cy; + } + if (ocx != cx) { + if (cx != cy) { + if (cx > 0) { + ypcx = y + cx; + ymcx = y - cx; + result |= hlineColor(dst, xmcy, xpcy, ymcx, color); + result |= hlineColor(dst, xmcy, xpcy, ypcx, color); + } else { + result |= hlineColor(dst, xmcy, xpcy, y, color); + } + } + ocx = cx; + } + /* + * Update + */ + if (df < 0) { + df += d_e; + d_e += 2; + d_se += 2; + } else { + df += d_se; + d_e += 2; + d_se += 4; + cy--; + } + cx++; + } while (cx <= cy); + + return (result); +} + +/*! +\brief Draw filled circle with blending. + +\param dst The surface to draw on. +\param x X coordinate of the center of the filled circle. +\param y Y coordinate of the center of the filled circle. +\param rad Radius in pixels of the filled circle. +\param r The red value of the filled circle to draw. +\param g The green value of the filled circle to draw. +\param b The blue value of the filled circle to draw. +\param a The alpha value of the filled circle to draw. + +\returns Returns 0 on success, -1 on failure. +*/ +int filledCircleRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + /* + * Draw + */ + return (filledCircleColor + (dst, x, y, rad, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a)); +} + +/* ----- Ellipse */ + +/*! +\brief Draw ellipse with blending. + +Note: Based on algorithms from sge library with modifications by A. Schiffler for +multiple-pixel draw removal and other minor speedup changes. + +\param dst The surface to draw on. +\param x X coordinate of the center of the ellipse. +\param y Y coordinate of the center of the ellipse. +\param rx Horizontal radius in pixels of the ellipse. +\param ry Vertical radius in pixels of the ellipse. +\param color The color value of the ellipse to draw (0xRRGGBBAA). + +\returns Returns 0 on success, -1 on failure. +*/ +int ellipseColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint32 color) +{ + Sint16 left, right, top, bottom; + int result; + Sint16 x1, y1, x2, y2; + int ix, iy; + int h, i, j, k; + int oh, oi, oj, ok; + int xmh, xph, ypk, ymk; + int xmi, xpi, ymj, ypj; + int xmj, xpj, ymi, ypi; + int xmk, xpk, ymh, yph; + Uint8 *colorptr; + + /* + * Check visibility of clipping rectangle + */ + if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) { + return(0); + } + + /* + * Sanity check radii + */ + if ((rx < 0) || (ry < 0)) { + return (-1); + } + + /* + * Special case for rx=0 - draw a vline + */ + if (rx == 0) { + return (vlineColor(dst, x, y - ry, y + ry, color)); + } + /* + * Special case for ry=0 - draw a hline + */ + if (ry == 0) { + return (hlineColor(dst, x - rx, x + rx, y, color)); + } + + /* + * Get circle and clipping boundary and + * test if bounding box of circle is visible + */ + x2 = x + rx; + left = dst->clip_rect.x; + if (x2clip_rect.x + dst->clip_rect.w - 1; + if (x1>right) { + return(0); + } + y2 = y + ry; + top = dst->clip_rect.y; + if (y2clip_rect.y + dst->clip_rect.h - 1; + if (y1>bottom) { + return(0); + } + + /* + * Init vars + */ + oh = oi = oj = ok = 0xFFFF; + + /* + * Draw + */ + result = 0; + + /* Lock surface */ + if (SDL_MUSTLOCK(dst)) { + if (SDL_LockSurface(dst) < 0) { + return (-1); + } + } + + /* + * Check alpha + */ + if ((color & 255) == 255) { + + /* + * No Alpha - direct memory writes + */ + + /* + * Setup color + */ + colorptr = (Uint8 *) & color; + if (SDL_BYTEORDER == SDL_BIG_ENDIAN) { + color = SDL_MapRGBA(dst->format, colorptr[0], colorptr[1], colorptr[2], colorptr[3]); + } else { + color = SDL_MapRGBA(dst->format, colorptr[3], colorptr[2], colorptr[1], colorptr[0]); + } + + + if (rx > ry) { + ix = 0; + iy = rx * 64; + + do { + h = (ix + 32) >> 6; + i = (iy + 32) >> 6; + j = (h * ry) / rx; + k = (i * ry) / rx; + + if (((ok != k) && (oj != k)) || ((oj != j) && (ok != j)) || (k != j)) { + xph = x + h; + xmh = x - h; + if (k > 0) { + ypk = y + k; + ymk = y - k; + result |= fastPixelColorNolock(dst, xmh, ypk, color); + result |= fastPixelColorNolock(dst, xph, ypk, color); + result |= fastPixelColorNolock(dst, xmh, ymk, color); + result |= fastPixelColorNolock(dst, xph, ymk, color); + } else { + result |= fastPixelColorNolock(dst, xmh, y, color); + result |= fastPixelColorNolock(dst, xph, y, color); + } + ok = k; + xpi = x + i; + xmi = x - i; + if (j > 0) { + ypj = y + j; + ymj = y - j; + result |= fastPixelColorNolock(dst, xmi, ypj, color); + result |= fastPixelColorNolock(dst, xpi, ypj, color); + result |= fastPixelColorNolock(dst, xmi, ymj, color); + result |= fastPixelColorNolock(dst, xpi, ymj, color); + } else { + result |= fastPixelColorNolock(dst, xmi, y, color); + result |= fastPixelColorNolock(dst, xpi, y, color); + } + oj = j; + } + + ix = ix + iy / rx; + iy = iy - ix / rx; + + } while (i > h); + } else { + ix = 0; + iy = ry * 64; + + do { + h = (ix + 32) >> 6; + i = (iy + 32) >> 6; + j = (h * rx) / ry; + k = (i * rx) / ry; + + if (((oi != i) && (oh != i)) || ((oh != h) && (oi != h) && (i != h))) { + xmj = x - j; + xpj = x + j; + if (i > 0) { + ypi = y + i; + ymi = y - i; + result |= fastPixelColorNolock(dst, xmj, ypi, color); + result |= fastPixelColorNolock(dst, xpj, ypi, color); + result |= fastPixelColorNolock(dst, xmj, ymi, color); + result |= fastPixelColorNolock(dst, xpj, ymi, color); + } else { + result |= fastPixelColorNolock(dst, xmj, y, color); + result |= fastPixelColorNolock(dst, xpj, y, color); + } + oi = i; + xmk = x - k; + xpk = x + k; + if (h > 0) { + yph = y + h; + ymh = y - h; + result |= fastPixelColorNolock(dst, xmk, yph, color); + result |= fastPixelColorNolock(dst, xpk, yph, color); + result |= fastPixelColorNolock(dst, xmk, ymh, color); + result |= fastPixelColorNolock(dst, xpk, ymh, color); + } else { + result |= fastPixelColorNolock(dst, xmk, y, color); + result |= fastPixelColorNolock(dst, xpk, y, color); + } + oh = h; + } + + ix = ix + iy / ry; + iy = iy - ix / ry; + + } while (i > h); + } + + } else { + + if (rx > ry) { + ix = 0; + iy = rx * 64; + + do { + h = (ix + 32) >> 6; + i = (iy + 32) >> 6; + j = (h * ry) / rx; + k = (i * ry) / rx; + + if (((ok != k) && (oj != k)) || ((oj != j) && (ok != j)) || (k != j)) { + xph = x + h; + xmh = x - h; + if (k > 0) { + ypk = y + k; + ymk = y - k; + result |= pixelColorNolock (dst, xmh, ypk, color); + result |= pixelColorNolock (dst, xph, ypk, color); + result |= pixelColorNolock (dst, xmh, ymk, color); + result |= pixelColorNolock (dst, xph, ymk, color); + } else { + result |= pixelColorNolock (dst, xmh, y, color); + result |= pixelColorNolock (dst, xph, y, color); + } + ok = k; + xpi = x + i; + xmi = x - i; + if (j > 0) { + ypj = y + j; + ymj = y - j; + result |= pixelColorNolock (dst, xmi, ypj, color); + result |= pixelColorNolock (dst, xpi, ypj, color); + result |= pixelColorNolock (dst, xmi, ymj, color); + result |= pixelColor(dst, xpi, ymj, color); + } else { + result |= pixelColorNolock (dst, xmi, y, color); + result |= pixelColorNolock (dst, xpi, y, color); + } + oj = j; + } + + ix = ix + iy / rx; + iy = iy - ix / rx; + + } while (i > h); + } else { + ix = 0; + iy = ry * 64; + + do { + h = (ix + 32) >> 6; + i = (iy + 32) >> 6; + j = (h * rx) / ry; + k = (i * rx) / ry; + + if (((oi != i) && (oh != i)) || ((oh != h) && (oi != h) && (i != h))) { + xmj = x - j; + xpj = x + j; + if (i > 0) { + ypi = y + i; + ymi = y - i; + result |= pixelColorNolock (dst, xmj, ypi, color); + result |= pixelColorNolock (dst, xpj, ypi, color); + result |= pixelColorNolock (dst, xmj, ymi, color); + result |= pixelColorNolock (dst, xpj, ymi, color); + } else { + result |= pixelColorNolock (dst, xmj, y, color); + result |= pixelColorNolock (dst, xpj, y, color); + } + oi = i; + xmk = x - k; + xpk = x + k; + if (h > 0) { + yph = y + h; + ymh = y - h; + result |= pixelColorNolock (dst, xmk, yph, color); + result |= pixelColorNolock (dst, xpk, yph, color); + result |= pixelColorNolock (dst, xmk, ymh, color); + result |= pixelColorNolock (dst, xpk, ymh, color); + } else { + result |= pixelColorNolock (dst, xmk, y, color); + result |= pixelColorNolock (dst, xpk, y, color); + } + oh = h; + } + + ix = ix + iy / ry; + iy = iy - ix / ry; + + } while (i > h); + } + + } /* Alpha check */ + + /* Unlock surface */ + if (SDL_MUSTLOCK(dst)) { + SDL_UnlockSurface(dst); + } + + return (result); +} + +/*! +\brief Draw ellipse with blending. + +\param dst The surface to draw on. +\param x X coordinate of the center of the ellipse. +\param y Y coordinate of the center of the ellipse. +\param rx Horizontal radius in pixels of the ellipse. +\param ry Vertical radius in pixels of the ellipse. +\param r The red value of the ellipse to draw. +\param g The green value of the ellipse to draw. +\param b The blue value of the ellipse to draw. +\param a The alpha value of the ellipse to draw. + +\returns Returns 0 on success, -1 on failure. +*/ +int ellipseRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + /* + * Draw + */ + return (ellipseColor(dst, x, y, rx, ry, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a)); +} + +/* ----- AA Ellipse */ + +/* Win32 does not have lrint, so provide a local inline version */ +#if defined(_MSC_VER) +/* Detect 64bit and use intrinsic version */ +#ifdef _M_X64 +#include +static __inline long +lrint(float f) +{ + return _mm_cvtss_si32(_mm_load_ss(&f)); +} +#elif defined(_M_IX86) +__inline long int +lrint (double flt) +{ + int intgr; + _asm + { + fld flt + fistp intgr + }; + return intgr; +} +#else +#error lrint needed for MSVC on non X86/AMD64 targets. +#endif +#endif + +/*! +\brief Draw anti-aliased ellipse with blending. + +Note: Based on code from Anders Lindstroem, which is based on code from sge library, +which is based on code from TwinLib. + +\param dst The surface to draw on. +\param x X coordinate of the center of the aa-ellipse. +\param y Y coordinate of the center of the aa-ellipse. +\param rx Horizontal radius in pixels of the aa-ellipse. +\param ry Vertical radius in pixels of the aa-ellipse. +\param color The color value of the aa-ellipse to draw (0xRRGGBBAA). + +\returns Returns 0 on success, -1 on failure. +*/ +int aaellipseColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint32 color) +{ + Sint16 left, right, top, bottom; + Sint16 x1,y1,x2,y2; + int i; + int a2, b2, ds, dt, dxt, t, s, d; + Sint16 xp, yp, xs, ys, dyt, od, xx, yy, xc2, yc2; + float cp; + double sab; + Uint8 weight, iweight; + int result; + + /* + * Check visibility of clipping rectangle + */ + if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) { + return(0); + } + + /* + * Sanity check radii + */ + if ((rx < 0) || (ry < 0)) { + return (-1); + } + + /* + * Special case for rx=0 - draw a vline + */ + if (rx == 0) { + return (vlineColor(dst, x, y - ry, y + ry, color)); + } + /* + * Special case for ry=0 - draw an hline + */ + if (ry == 0) { + return (hlineColor(dst, x - rx, x + rx, y, color)); + } + + /* + * Get circle and clipping boundary and + * test if bounding box of circle is visible + */ + x2 = x + rx; + left = dst->clip_rect.x; + if (x2clip_rect.x + dst->clip_rect.w - 1; + if (x1>right) { + return(0); + } + y2 = y + ry; + top = dst->clip_rect.y; + if (y2clip_rect.y + dst->clip_rect.h - 1; + if (y1>bottom) { + return(0); + } + + /* Variable setup */ + a2 = rx * rx; + b2 = ry * ry; + + ds = 2 * a2; + dt = 2 * b2; + + xc2 = 2 * x; + yc2 = 2 * y; + + sab = sqrt(a2 + b2); + od = (Sint16)lrint(sab*0.01) + 1; /* introduce some overdraw */ + dxt = (Sint16)lrint((double)a2 / sab) + od; + + t = 0; + s = -2 * a2 * ry; + d = 0; + + xp = x; + yp = y - ry; + + /* Lock surface */ + if (SDL_MUSTLOCK(dst)) { + if (SDL_LockSurface(dst) < 0) { + return (-1); + } + } + + /* Draw */ + result = 0; + + /* "End points" */ + result |= pixelColorNolock(dst, xp, yp, color); + result |= pixelColorNolock(dst, xc2 - xp, yp, color); + result |= pixelColorNolock(dst, xp, yc2 - yp, color); + result |= pixelColorNolock(dst, xc2 - xp, yc2 - yp, color); + + for (i = 1; i <= dxt; i++) { + xp--; + d += t - b2; + + if (d >= 0) + ys = yp - 1; + else if ((d - s - a2) > 0) { + if ((2 * d - s - a2) >= 0) + ys = yp + 1; + else { + ys = yp; + yp++; + d -= s + a2; + s += ds; + } + } else { + yp++; + ys = yp + 1; + d -= s + a2; + s += ds; + } + + t -= dt; + + /* Calculate alpha */ + if (s != 0.0) { + cp = (float) abs(d) / (float) abs(s); + if (cp > 1.0) { + cp = 1.0; + } + } else { + cp = 1.0; + } + + /* Calculate weights */ + weight = (Uint8) (cp * 255); + iweight = 255 - weight; + + /* Upper half */ + xx = xc2 - xp; + result |= pixelColorWeightNolock(dst, xp, yp, color, iweight); + result |= pixelColorWeightNolock(dst, xx, yp, color, iweight); + + result |= pixelColorWeightNolock(dst, xp, ys, color, weight); + result |= pixelColorWeightNolock(dst, xx, ys, color, weight); + + /* Lower half */ + yy = yc2 - yp; + result |= pixelColorWeightNolock(dst, xp, yy, color, iweight); + result |= pixelColorWeightNolock(dst, xx, yy, color, iweight); + + yy = yc2 - ys; + result |= pixelColorWeightNolock(dst, xp, yy, color, weight); + result |= pixelColorWeightNolock(dst, xx, yy, color, weight); + } + + /* Replaces original approximation code dyt = abs(yp - yc); */ + dyt = (Sint16)lrint((double)b2 / sab ) + od; + + for (i = 1; i <= dyt; i++) { + yp++; + d -= s + a2; + + if (d <= 0) + xs = xp + 1; + else if ((d + t - b2) < 0) { + if ((2 * d + t - b2) <= 0) + xs = xp - 1; + else { + xs = xp; + xp--; + d += t - b2; + t -= dt; + } + } else { + xp--; + xs = xp - 1; + d += t - b2; + t -= dt; + } + + s += ds; + + /* Calculate alpha */ + if (t != 0.0) { + cp = (float) abs(d) / (float) abs(t); + if (cp > 1.0) { + cp = 1.0; + } + } else { + cp = 1.0; + } + + /* Calculate weight */ + weight = (Uint8) (cp * 255); + iweight = 255 - weight; + + /* Left half */ + xx = xc2 - xp; + yy = yc2 - yp; + result |= pixelColorWeightNolock(dst, xp, yp, color, iweight); + result |= pixelColorWeightNolock(dst, xx, yp, color, iweight); + + result |= pixelColorWeightNolock(dst, xp, yy, color, iweight); + result |= pixelColorWeightNolock(dst, xx, yy, color, iweight); + + /* Right half */ + xx = xc2 - xs; + result |= pixelColorWeightNolock(dst, xs, yp, color, weight); + result |= pixelColorWeightNolock(dst, xx, yp, color, weight); + + result |= pixelColorWeightNolock(dst, xs, yy, color, weight); + result |= pixelColorWeightNolock(dst, xx, yy, color, weight); + + } + + /* Unlock surface */ + if (SDL_MUSTLOCK(dst)) { + SDL_UnlockSurface(dst); + } + + return (result); +} + +/*! +\brief Draw anti-aliased ellipse with blending. + +\param dst The surface to draw on. +\param x X coordinate of the center of the aa-ellipse. +\param y Y coordinate of the center of the aa-ellipse. +\param rx Horizontal radius in pixels of the aa-ellipse. +\param ry Vertical radius in pixels of the aa-ellipse. +\param r The red value of the aa-ellipse to draw. +\param g The green value of the aa-ellipse to draw. +\param b The blue value of the aa-ellipse to draw. +\param a The alpha value of the aa-ellipse to draw. + +\returns Returns 0 on success, -1 on failure. +*/ +int aaellipseRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + /* + * Draw + */ + return (aaellipseColor + (dst, x, y, rx, ry, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a)); +} + +/* ---- Filled Ellipse */ + +/* Note: */ +/* Based on algorithm from sge library with multiple-hline draw removal */ +/* and other speedup changes. */ + +/*! +\brief Draw filled ellipse with blending. + +Note: Based on algorithm from sge library with multiple-hline draw removal +and other speedup changes. + +\param dst The surface to draw on. +\param x X coordinate of the center of the filled ellipse. +\param y Y coordinate of the center of the filled ellipse. +\param rx Horizontal radius in pixels of the filled ellipse. +\param ry Vertical radius in pixels of the filled ellipse. +\param color The color value of the filled ellipse to draw (0xRRGGBBAA). + +\returns Returns 0 on success, -1 on failure. +*/ +int filledEllipseColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint32 color) +{ + Sint16 left, right, top, bottom; + int result; + Sint16 x1, y1, x2, y2; + int ix, iy; + int h, i, j, k; + int oh, oi, oj, ok; + int xmh, xph; + int xmi, xpi; + int xmj, xpj; + int xmk, xpk; + + /* + * Check visibility of clipping rectangle + */ + if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) { + return(0); + } + + /* + * Sanity check radii + */ + if ((rx < 0) || (ry < 0)) { + return (-1); + } + + /* + * Special case for rx=0 - draw a vline + */ + if (rx == 0) { + return (vlineColor(dst, x, y - ry, y + ry, color)); + } + /* + * Special case for ry=0 - draw a hline + */ + if (ry == 0) { + return (hlineColor(dst, x - rx, x + rx, y, color)); + } + + /* + * Get circle and clipping boundary and + * test if bounding box of circle is visible + */ + x2 = x + rx; + left = dst->clip_rect.x; + if (x2clip_rect.x + dst->clip_rect.w - 1; + if (x1>right) { + return(0); + } + y2 = y + ry; + top = dst->clip_rect.y; + if (y2clip_rect.y + dst->clip_rect.h - 1; + if (y1>bottom) { + return(0); + } + + /* + * Init vars + */ + oh = oi = oj = ok = 0xFFFF; + + /* + * Draw + */ + result = 0; + if (rx > ry) { + ix = 0; + iy = rx * 64; + + do { + h = (ix + 32) >> 6; + i = (iy + 32) >> 6; + j = (h * ry) / rx; + k = (i * ry) / rx; + + if ((ok != k) && (oj != k)) { + xph = x + h; + xmh = x - h; + if (k > 0) { + result |= hlineColor(dst, xmh, xph, y + k, color); + result |= hlineColor(dst, xmh, xph, y - k, color); + } else { + result |= hlineColor(dst, xmh, xph, y, color); + } + ok = k; + } + if ((oj != j) && (ok != j) && (k != j)) { + xmi = x - i; + xpi = x + i; + if (j > 0) { + result |= hlineColor(dst, xmi, xpi, y + j, color); + result |= hlineColor(dst, xmi, xpi, y - j, color); + } else { + result |= hlineColor(dst, xmi, xpi, y, color); + } + oj = j; + } + + ix = ix + iy / rx; + iy = iy - ix / rx; + + } while (i > h); + } else { + ix = 0; + iy = ry * 64; + + do { + h = (ix + 32) >> 6; + i = (iy + 32) >> 6; + j = (h * rx) / ry; + k = (i * rx) / ry; + + if ((oi != i) && (oh != i)) { + xmj = x - j; + xpj = x + j; + if (i > 0) { + result |= hlineColor(dst, xmj, xpj, y + i, color); + result |= hlineColor(dst, xmj, xpj, y - i, color); + } else { + result |= hlineColor(dst, xmj, xpj, y, color); + } + oi = i; + } + if ((oh != h) && (oi != h) && (i != h)) { + xmk = x - k; + xpk = x + k; + if (h > 0) { + result |= hlineColor(dst, xmk, xpk, y + h, color); + result |= hlineColor(dst, xmk, xpk, y - h, color); + } else { + result |= hlineColor(dst, xmk, xpk, y, color); + } + oh = h; + } + + ix = ix + iy / ry; + iy = iy - ix / ry; + + } while (i > h); + } + + return (result); +} + +/*! +\brief Draw filled ellipse with blending. + +\param dst The surface to draw on. +\param x X coordinate of the center of the filled ellipse. +\param y Y coordinate of the center of the filled ellipse. +\param rx Horizontal radius in pixels of the filled ellipse. +\param ry Vertical radius in pixels of the filled ellipse. +\param r The red value of the filled ellipse to draw. +\param g The green value of the filled ellipse to draw. +\param b The blue value of the filled ellipse to draw. +\param a The alpha value of the filled ellipse to draw. + +\returns Returns 0 on success, -1 on failure. +*/ +int filledEllipseRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + /* + * Draw + */ + return (filledEllipseColor + (dst, x, y, rx, ry, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a)); +} + +/* ----- pie */ + +/*! +\brief Internal float (low-speed) pie-calc implementation by drawing polygons. + +Note: Determines vertex array and uses polygon or filledPolygon drawing routines to render. + +\param dst The surface to draw on. +\param x X coordinate of the center of the pie. +\param y Y coordinate of the center of the pie. +\param rad Radius in pixels of the pie. +\param start Starting radius in degrees of the pie. +\param end Ending radius in degrees of the pie. +\param color The color value of the pie to draw (0xRRGGBBAA). +\param filled Flag indicating if the pie should be filled (=1) or not (=0). + +\returns Returns 0 on success, -1 on failure. +*/ +int _pieColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad, Sint16 start, Sint16 end, Uint32 color, Uint8 filled) +{ + Sint16 left, right, top, bottom; + Sint16 x1, y1, x2, y2; + int result; + double angle, start_angle, end_angle; + double deltaAngle; + double dr; + int numpoints, i; + Sint16 *vx, *vy; + + /* + * Check visibility of clipping rectangle + */ + if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) { + return(0); + } + + /* + * Sanity check radii + */ + if (rad < 0) { + return (-1); + } + + /* + * Fixup angles + */ + start = start % 360; + end = end % 360; + + /* + * Special case for rad=0 - draw a point + */ + if (rad == 0) { + return (pixelColor(dst, x, y, color)); + } + + /* + * Clip against circle, not pie (not 100% optimal). + * Get pie's circle and clipping boundary and + * test if bounding box of circle is visible + */ + x2 = x + rad; + left = dst->clip_rect.x; + if (x2clip_rect.x + dst->clip_rect.w - 1; + if (x1>right) { + return(0); + } + y2 = y + rad; + top = dst->clip_rect.y; + if (y2clip_rect.y + dst->clip_rect.h - 1; + if (y1>bottom) { + return(0); + } + + /* + * Variable setup + */ + dr = (double) rad; + deltaAngle = 3.0 / dr; + start_angle = (double) start *(2.0 * M_PI / 360.0); + end_angle = (double) end *(2.0 * M_PI / 360.0); + if (start > end) { + end_angle += (2.0 * M_PI); + } + + /* We will always have at least 2 points */ + numpoints = 2; + + /* Count points (rather than calculating it) */ + angle = start_angle; + while (angle < end_angle) { + angle += deltaAngle; + numpoints++; + } + + /* Allocate combined vertex array */ + vx = vy = (Sint16 *) malloc(2 * sizeof(Uint16) * numpoints); + if (vx == NULL) { + return (-1); + } + + /* Update point to start of vy */ + vy += numpoints; + + /* Center */ + vx[0] = x; + vy[0] = y; + + /* First vertex */ + angle = start_angle; + vx[1] = x + (int) (dr * cos(angle)); + vy[1] = y + (int) (dr * sin(angle)); + + if (numpoints<3) + { + result = lineColor(dst, vx[0], vy[0], vx[1], vy[1], color); + } + else + { + /* Calculate other vertices */ + i = 2; + angle = start_angle; + while (angle < end_angle) { + angle += deltaAngle; + if (angle>end_angle) + { + angle = end_angle; + } + vx[i] = x + (int) (dr * cos(angle)); + vy[i] = y + (int) (dr * sin(angle)); + i++; + } + + /* Draw */ + if (filled) { + result = filledPolygonColor(dst, vx, vy, numpoints, color); + } else { + result = polygonColor(dst, vx, vy, numpoints, color); + } + } + + /* Free combined vertex array */ + free(vx); + + return (result); +} + +/*! +\brief Draw pie (outline) with alpha blending. + +\param dst The surface to draw on. +\param x X coordinate of the center of the pie. +\param y Y coordinate of the center of the pie. +\param rad Radius in pixels of the pie. +\param start Starting radius in degrees of the pie. +\param end Ending radius in degrees of the pie. +\param color The color value of the pie to draw (0xRRGGBBAA). + +\returns Returns 0 on success, -1 on failure. +*/ +int pieColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad, + Sint16 start, Sint16 end, Uint32 color) +{ + return (_pieColor(dst, x, y, rad, start, end, color, 0)); + +} + +/*! +\brief Draw pie (outline) with alpha blending. + +\param dst The surface to draw on. +\param x X coordinate of the center of the pie. +\param y Y coordinate of the center of the pie. +\param rad Radius in pixels of the pie. +\param start Starting radius in degrees of the pie. +\param end Ending radius in degrees of the pie. +\param r The red value of the pie to draw. +\param g The green value of the pie to draw. +\param b The blue value of the pie to draw. +\param a The alpha value of the pie to draw. + +\returns Returns 0 on success, -1 on failure. +*/ +int pieRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad, + Sint16 start, Sint16 end, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + return (_pieColor(dst, x, y, rad, start, end, + ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a, 0)); + +} + +/*! +\brief Draw filled pie with alpha blending. + +\param dst The surface to draw on. +\param x X coordinate of the center of the filled pie. +\param y Y coordinate of the center of the filled pie. +\param rad Radius in pixels of the filled pie. +\param start Starting radius in degrees of the filled pie. +\param end Ending radius in degrees of the filled pie. +\param color The color value of the filled pie to draw (0xRRGGBBAA). + +\returns Returns 0 on success, -1 on failure. +*/ +int filledPieColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad, Sint16 start, Sint16 end, Uint32 color) +{ + return (_pieColor(dst, x, y, rad, start, end, color, 1)); +} + +/*! +\brief Draw filled pie with alpha blending. + +\param dst The surface to draw on. +\param x X coordinate of the center of the filled pie. +\param y Y coordinate of the center of the filled pie. +\param rad Radius in pixels of the filled pie. +\param start Starting radius in degrees of the filled pie. +\param end Ending radius in degrees of the filled pie. +\param r The red value of the filled pie to draw. +\param g The green value of the filled pie to draw. +\param b The blue value of the filled pie to draw. +\param a The alpha value of the filled pie to draw. + +\returns Returns 0 on success, -1 on failure. +*/ +int filledPieRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad, + Sint16 start, Sint16 end, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + return (_pieColor(dst, x, y, rad, start, end, + ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a, 1)); +} + +/* ------ Trigon */ + +/*! +\brief Draw trigon (triangle outline) with alpha blending. + +Note: Creates vertex array and uses polygon routine to render. + +\param dst The surface to draw on. +\param x1 X coordinate of the first point of the trigon. +\param y1 Y coordinate of the first point of the trigon. +\param x2 X coordinate of the second point of the trigon. +\param y2 Y coordinate of the second point of the trigon. +\param x3 X coordinate of the third point of the trigon. +\param y3 Y coordinate of the third point of the trigon. +\param color The color value of the trigon to draw (0xRRGGBBAA). + +\returns Returns 0 on success, -1 on failure. +*/ +int trigonColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, Uint32 color) +{ + Sint16 vx[3]; + Sint16 vy[3]; + + vx[0]=x1; + vx[1]=x2; + vx[2]=x3; + vy[0]=y1; + vy[1]=y2; + vy[2]=y3; + + return(polygonColor(dst,vx,vy,3,color)); +} + +/*! +\brief Draw trigon (triangle outline) with alpha blending. + +\param dst The surface to draw on. +\param x1 X coordinate of the first point of the trigon. +\param y1 Y coordinate of the first point of the trigon. +\param x2 X coordinate of the second point of the trigon. +\param y2 Y coordinate of the second point of the trigon. +\param x3 X coordinate of the third point of the trigon. +\param y3 Y coordinate of the third point of the trigon. +\param r The red value of the trigon to draw. +\param g The green value of the trigon to draw. +\param b The blue value of the trigon to draw. +\param a The alpha value of the trigon to draw. + +\returns Returns 0 on success, -1 on failure. +*/ +int trigonRGBA(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, + Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + Sint16 vx[3]; + Sint16 vy[3]; + + vx[0]=x1; + vx[1]=x2; + vx[2]=x3; + vy[0]=y1; + vy[1]=y2; + vy[2]=y3; + + return(polygonRGBA(dst,vx,vy,3,r,g,b,a)); +} + +/* ------ AA-Trigon */ + +/*! +\brief Draw anti-aliased trigon (triangle outline) with alpha blending. + +Note: Creates vertex array and uses aapolygon routine to render. + +\param dst The surface to draw on. +\param x1 X coordinate of the first point of the aa-trigon. +\param y1 Y coordinate of the first point of the aa-trigon. +\param x2 X coordinate of the second point of the aa-trigon. +\param y2 Y coordinate of the second point of the aa-trigon. +\param x3 X coordinate of the third point of the aa-trigon. +\param y3 Y coordinate of the third point of the aa-trigon. +\param color The color value of the aa-trigon to draw (0xRRGGBBAA). + +\returns Returns 0 on success, -1 on failure. +*/ +int aatrigonColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, Uint32 color) +{ + Sint16 vx[3]; + Sint16 vy[3]; + + vx[0]=x1; + vx[1]=x2; + vx[2]=x3; + vy[0]=y1; + vy[1]=y2; + vy[2]=y3; + + return(aapolygonColor(dst,vx,vy,3,color)); +} + +/*! +\brief Draw anti-aliased trigon (triangle outline) with alpha blending. + +\param dst The surface to draw on. +\param x1 X coordinate of the first point of the aa-trigon. +\param y1 Y coordinate of the first point of the aa-trigon. +\param x2 X coordinate of the second point of the aa-trigon. +\param y2 Y coordinate of the second point of the aa-trigon. +\param x3 X coordinate of the third point of the aa-trigon. +\param y3 Y coordinate of the third point of the aa-trigon. +\param r The red value of the aa-trigon to draw. +\param g The green value of the aa-trigon to draw. +\param b The blue value of the aa-trigon to draw. +\param a The alpha value of the aa-trigon to draw. + +\returns Returns 0 on success, -1 on failure. +*/ +int aatrigonRGBA(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, + Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + Sint16 vx[3]; + Sint16 vy[3]; + + vx[0]=x1; + vx[1]=x2; + vx[2]=x3; + vy[0]=y1; + vy[1]=y2; + vy[2]=y3; + + return(aapolygonRGBA(dst,vx,vy,3,r,g,b,a)); +} + +/* ------ Filled Trigon */ + +/*! +\brief Draw filled trigon (triangle) with alpha blending. + +Note: Creates vertex array and uses aapolygon routine to render. + +\param dst The surface to draw on. +\param x1 X coordinate of the first point of the filled trigon. +\param y1 Y coordinate of the first point of the filled trigon. +\param x2 X coordinate of the second point of the filled trigon. +\param y2 Y coordinate of the second point of the filled trigon. +\param x3 X coordinate of the third point of the filled trigon. +\param y3 Y coordinate of the third point of the filled trigon. +\param color The color value of the filled trigon to draw (0xRRGGBBAA). + +\returns Returns 0 on success, -1 on failure. +*/ +int filledTrigonColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, Uint32 color) +{ + Sint16 vx[3]; + Sint16 vy[3]; + + vx[0]=x1; + vx[1]=x2; + vx[2]=x3; + vy[0]=y1; + vy[1]=y2; + vy[2]=y3; + + return(filledPolygonColor(dst,vx,vy,3,color)); +} + +/*! +\brief Draw filled trigon (triangle) with alpha blending. + +Note: Creates vertex array and uses aapolygon routine to render. + +\param dst The surface to draw on. +\param x1 X coordinate of the first point of the filled trigon. +\param y1 Y coordinate of the first point of the filled trigon. +\param x2 X coordinate of the second point of the filled trigon. +\param y2 Y coordinate of the second point of the filled trigon. +\param x3 X coordinate of the third point of the filled trigon. +\param y3 Y coordinate of the third point of the filled trigon. +\param r The red value of the filled trigon to draw. +\param g The green value of the filled trigon to draw. +\param b The blue value of the filled trigon to draw. +\param a The alpha value of the filled trigon to draw. + +\returns Returns 0 on success, -1 on failure. +*/ +int filledTrigonRGBA(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, + Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + Sint16 vx[3]; + Sint16 vy[3]; + + vx[0]=x1; + vx[1]=x2; + vx[2]=x3; + vy[0]=y1; + vy[1]=y2; + vy[2]=y3; + + return(filledPolygonRGBA(dst,vx,vy,3,r,g,b,a)); +} + +/* ---- Polygon */ + +/*! +\brief Draw polygon with alpha blending. + +\param dst The surface to draw on. +\param vx Vertex array containing X coordinates of the points of the polygon. +\param vy Vertex array containing Y coordinates of the points of the polygon. +\param n Number of points in the vertex array. Minimum number is 3. +\param color The color value of the polygon to draw (0xRRGGBBAA). + +\returns Returns 0 on success, -1 on failure. +*/ +int polygonColor(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, Uint32 color) +{ + int result; + int i; + const Sint16 *x1, *y1, *x2, *y2; + + /* + * Check visibility of clipping rectangle + */ + if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) { + return(0); + } + + /* + * Vertex array NULL check + */ + if (vx == NULL) { + return (-1); + } + if (vy == NULL) { + return (-1); + } + + /* + * Sanity check + */ + if (n < 3) { + return (-1); + } + + /* + * Pointer setup + */ + x1 = x2 = vx; + y1 = y2 = vy; + x2++; + y2++; + + /* + * Draw + */ + result = 0; + for (i = 1; i < n; i++) { + result |= lineColor(dst, *x1, *y1, *x2, *y2, color); + x1 = x2; + y1 = y2; + x2++; + y2++; + } + result |= lineColor(dst, *x1, *y1, *vx, *vy, color); + + return (result); +} + +/*! +\brief Draw polygon with alpha blending. + +\param dst The surface to draw on. +\param vx Vertex array containing X coordinates of the points of the polygon. +\param vy Vertex array containing Y coordinates of the points of the polygon. +\param n Number of points in the vertex array. Minimum number is 3. +\param r The red value of the polygon to draw. +\param g The green value of the polygon to draw. +\param b The blue value of the polygon to draw. +\param a The alpha value of the polygon to draw. + +\returns Returns 0 on success, -1 on failure. +*/ +int polygonRGBA(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + /* + * Draw + */ + return (polygonColor(dst, vx, vy, n, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a)); +} + +/* ---- AA-Polygon */ + +/*! +\brief Draw anti-aliased polygon with alpha blending. + +\param dst The surface to draw on. +\param vx Vertex array containing X coordinates of the points of the aa-polygon. +\param vy Vertex array containing Y coordinates of the points of the aa-polygon. +\param n Number of points in the vertex array. Minimum number is 3. +\param color The color value of the aa-polygon to draw (0xRRGGBBAA). + +\returns Returns 0 on success, -1 on failure. +*/ +int aapolygonColor(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, Uint32 color) +{ + int result; + int i; + const Sint16 *x1, *y1, *x2, *y2; + + /* + * Check visibility of clipping rectangle + */ + if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) { + return(0); + } + + /* + * Vertex array NULL check + */ + if (vx == NULL) { + return (-1); + } + if (vy == NULL) { + return (-1); + } + + /* + * Sanity check + */ + if (n < 3) { + return (-1); + } + + /* + * Pointer setup + */ + x1 = x2 = vx; + y1 = y2 = vy; + x2++; + y2++; + + /* + * Draw + */ + result = 0; + for (i = 1; i < n; i++) { + result |= _aalineColor(dst, *x1, *y1, *x2, *y2, color, 0); + x1 = x2; + y1 = y2; + x2++; + y2++; + } + result |= _aalineColor(dst, *x1, *y1, *vx, *vy, color, 0); + + return (result); +} + +/*! +\brief Draw anti-aliased polygon with alpha blending. + +\param dst The surface to draw on. +\param vx Vertex array containing X coordinates of the points of the aa-polygon. +\param vy Vertex array containing Y coordinates of the points of the aa-polygon. +\param n Number of points in the vertex array. Minimum number is 3. +\param r The red value of the aa-polygon to draw. +\param g The green value of the aa-polygon to draw. +\param b The blue value of the aa-polygon to draw. +\param a The alpha value of the aa-polygon to draw. + +\returns Returns 0 on success, -1 on failure. +*/ +int aapolygonRGBA(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + /* + * Draw + */ + return (aapolygonColor(dst, vx, vy, n, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a)); +} + +/* ---- Filled Polygon */ + +/*! +\brief Internal helper qsort callback functions used in filled polygon drawing. + +\param a The surface to draw on. +\param b Vertex array containing X coordinates of the points of the polygon. + +\returns Returns 0 if a==b, a negative number if ab. +*/ +int _gfxPrimitivesCompareInt(const void *a, const void *b) +{ + return (*(const int *) a) - (*(const int *) b); +} + +/*! +\brief Global vertex array to use if optional parameters are not given in filledPolygonMT calls. + +Note: Used for non-multithreaded (default) operation of filledPolygonMT. +*/ +static int *gfxPrimitivesPolyIntsGlobal = NULL; + +/*! +\brief Flag indicating if global vertex array was already allocated. + +Note: Used for non-multithreaded (default) operation of filledPolygonMT. +*/ +static int gfxPrimitivesPolyAllocatedGlobal = 0; + +/*! +\brief Draw filled polygon with alpha blending (multi-threaded capable). + +Note: The last two parameters are optional; but are required for multithreaded operation. + +\param dst The surface to draw on. +\param vx Vertex array containing X coordinates of the points of the filled polygon. +\param vy Vertex array containing Y coordinates of the points of the filled polygon. +\param n Number of points in the vertex array. Minimum number is 3. +\param color The color value of the filled polygon to draw (0xRRGGBBAA). +\param polyInts Preallocated, temporary vertex array used for sorting vertices. Required for multithreaded operation; set to NULL otherwise. +\param polyAllocated Flag indicating if temporary vertex array was allocated. Required for multithreaded operation; set to NULL otherwise. + +\returns Returns 0 on success, -1 on failure. +*/ +int filledPolygonColorMT(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, Uint32 color, int **polyInts, int *polyAllocated) +{ + int result; + int i; + int y, xa, xb; + int miny, maxy; + int x1, y1; + int x2, y2; + int ind1, ind2; + int ints; + int *gfxPrimitivesPolyInts = NULL; + int gfxPrimitivesPolyAllocated = 0; + + /* + * Check visibility of clipping rectangle + */ + if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) { + return(0); + } + + /* + * Vertex array NULL check + */ + if (vx == NULL) { + return (-1); + } + if (vy == NULL) { + return (-1); + } + + /* + * Sanity check number of edges + */ + if (n < 3) { + return -1; + } + + /* + * Map polygon cache + */ + if ((polyInts==NULL) || (polyAllocated==NULL)) { + /* Use global cache */ + gfxPrimitivesPolyInts = gfxPrimitivesPolyIntsGlobal; + gfxPrimitivesPolyAllocated = gfxPrimitivesPolyAllocatedGlobal; + } else { + /* Use local cache */ + gfxPrimitivesPolyInts = *polyInts; + gfxPrimitivesPolyAllocated = *polyAllocated; + } + + /* + * Allocate temp array, only grow array + */ + if (!gfxPrimitivesPolyAllocated) { + gfxPrimitivesPolyInts = (int *) malloc(sizeof(int) * n); + gfxPrimitivesPolyAllocated = n; + } else { + if (gfxPrimitivesPolyAllocated < n) { + gfxPrimitivesPolyInts = (int *) realloc(gfxPrimitivesPolyInts, sizeof(int) * n); + gfxPrimitivesPolyAllocated = n; + } + } + + /* + * Check temp array + */ + if (gfxPrimitivesPolyInts==NULL) { + gfxPrimitivesPolyAllocated = 0; + } + + /* + * Update cache variables + */ + if ((polyInts==NULL) || (polyAllocated==NULL)) { + gfxPrimitivesPolyIntsGlobal = gfxPrimitivesPolyInts; + gfxPrimitivesPolyAllocatedGlobal = gfxPrimitivesPolyAllocated; + } else { + *polyInts = gfxPrimitivesPolyInts; + *polyAllocated = gfxPrimitivesPolyAllocated; + } + + /* + * Check temp array again + */ + if (gfxPrimitivesPolyInts==NULL) { + return(-1); + } + + /* + * Determine Y maxima + */ + miny = vy[0]; + maxy = vy[0]; + for (i = 1; (i < n); i++) { + if (vy[i] < miny) { + miny = vy[i]; + } else if (vy[i] > maxy) { + maxy = vy[i]; + } + } + + /* + * Draw, scanning y + */ + result = 0; + for (y = miny; (y <= maxy); y++) { + ints = 0; + for (i = 0; (i < n); i++) { + if (!i) { + ind1 = n - 1; + ind2 = 0; + } else { + ind1 = i - 1; + ind2 = i; + } + y1 = vy[ind1]; + y2 = vy[ind2]; + if (y1 < y2) { + x1 = vx[ind1]; + x2 = vx[ind2]; + } else if (y1 > y2) { + y2 = vy[ind1]; + y1 = vy[ind2]; + x2 = vx[ind1]; + x1 = vx[ind2]; + } else { + continue; + } + if ( ((y >= y1) && (y < y2)) || ((y == maxy) && (y > y1) && (y <= y2)) ) { + gfxPrimitivesPolyInts[ints++] = ((65536 * (y - y1)) / (y2 - y1)) * (x2 - x1) + (65536 * x1); + } + } + + qsort(gfxPrimitivesPolyInts, ints, sizeof(int), _gfxPrimitivesCompareInt); + + for (i = 0; (i < ints); i += 2) { + xa = gfxPrimitivesPolyInts[i] + 1; + xa = (xa >> 16) + ((xa & 32768) >> 15); + xb = gfxPrimitivesPolyInts[i+1] - 1; + xb = (xb >> 16) + ((xb & 32768) >> 15); + result |= hlineColor(dst, xa, xb, y, color); + } + } + + return (result); +} + +/*! +\brief Draw filled polygon with alpha blending (multi-threaded capable). + +Note: The last two parameters are optional; but are required for multithreaded operation. + +\param dst The surface to draw on. +\param vx Vertex array containing X coordinates of the points of the filled polygon. +\param vy Vertex array containing Y coordinates of the points of the filled polygon. +\param n Number of points in the vertex array. Minimum number is 3. +\param r The red value of the filled polygon to draw. +\param g The green value of the filled polygon to draw. +\param b The blue value of the filed polygon to draw. +\param a The alpha value of the filled polygon to draw. +\param polyInts Preallocated, temporary vertex array used for sorting vertices. Required for multithreaded operation; set to NULL otherwise. +\param polyAllocated Flag indicating if temporary vertex array was allocated. Required for multithreaded operation; set to NULL otherwise. + +\returns Returns 0 on success, -1 on failure. +*/ +int filledPolygonRGBAMT(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, Uint8 r, Uint8 g, Uint8 b, Uint8 a, int **polyInts, int *polyAllocated) +{ + /* + * Draw + */ + return (filledPolygonColorMT(dst, vx, vy, n, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a, polyInts, polyAllocated)); +} + +/*! +\brief Draw filled polygon with alpha blending. + +Note: Standard filledPolygon function is calling multithreaded version with NULL parameters +to use the global vertex cache. + +\param dst The surface to draw on. +\param vx Vertex array containing X coordinates of the points of the filled polygon. +\param vy Vertex array containing Y coordinates of the points of the filled polygon. +\param n Number of points in the vertex array. Minimum number is 3. +\param color The color value of the filled polygon to draw (0xRRGGBBAA). + +\returns Returns 0 on success, -1 on failure. +*/ +int filledPolygonColor(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, Uint32 color) +{ + /* + * Draw + */ + return (filledPolygonColorMT(dst, vx, vy, n, color, NULL, NULL)); +} + +/*! +\brief Draw filled polygon with alpha blending. + +\param dst The surface to draw on. +\param vx Vertex array containing X coordinates of the points of the filled polygon. +\param vy Vertex array containing Y coordinates of the points of the filled polygon. +\param n Number of points in the vertex array. Minimum number is 3. +\param r The red value of the filled polygon to draw. +\param g The green value of the filled polygon to draw. +\param b The blue value of the filed polygon to draw. +\param a The alpha value of the filled polygon to draw. + +\returns Returns 0 on success, -1 on failure. +*/ +int filledPolygonRGBA(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + /* + * Draw + */ + return (filledPolygonColorMT(dst, vx, vy, n, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a, NULL, NULL)); +} + +/*! +\brief Internal function to draw a textured horizontal line. + +\param dst The surface to draw on. +\param x1 X coordinate of the first point (i.e. left) of the line. +\param x2 X coordinate of the second point (i.e. right) of the line. +\param y Y coordinate of the points of the line. +\param texture The texture surface to retrieve color information from. +\param texture_dx The X offset for the texture lookup. +\param texture_dy The Y offset for the textured lookup. + +\returns Returns 0 on success, -1 on failure. +*/ +int _HLineTextured(SDL_Surface * dst, Sint16 x1, Sint16 x2, Sint16 y, SDL_Surface *texture, int texture_dx, int texture_dy) +{ + Sint16 left, right, top, bottom; + Sint16 w; + Sint16 xtmp; + int result = 0; + int texture_x_walker; + int texture_y_start; + SDL_Rect source_rect,dst_rect; + int pixels_written,write_width; + + /* + * Check visibility of clipping rectangle + */ + if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) { + return(0); + } + + /* + * Swap x1, x2 if required to ensure x1<=x2 + */ + if (x1 > x2) { + xtmp = x1; + x1 = x2; + x2 = xtmp; + } + + /* + * Get clipping boundary and + * check visibility of hline + */ + left = dst->clip_rect.x; + if (x2clip_rect.x + dst->clip_rect.w - 1; + if (x1>right) { + return(0); + } + top = dst->clip_rect.y; + bottom = dst->clip_rect.y + dst->clip_rect.h - 1; + if ((ybottom)) { + return (0); + } + + /* + * Clip x + */ + if (x1 < left) { + x1 = left; + } + if (x2 > right) { + x2 = right; + } + + /* + * Calculate width to draw + */ + w = x2 - x1 + 1; + + /* + * Determine where in the texture we start drawing + */ + texture_x_walker = (x1 - texture_dx) % texture->w; + if (texture_x_walker < 0){ + texture_x_walker = texture->w + texture_x_walker ; + } + + texture_y_start = (y + texture_dy) % texture->h; + if (texture_y_start < 0){ + texture_y_start = texture->h + texture_y_start; + } + + // setup the source rectangle; we are only drawing one horizontal line + source_rect.y = texture_y_start; + source_rect.x = texture_x_walker; + source_rect.h = 1; + + // we will draw to the current y + dst_rect.y = y; + + // if there are enough pixels left in the current row of the texture + // draw it all at once + if (w <= texture->w -texture_x_walker){ + source_rect.w = w; + source_rect.x = texture_x_walker; + dst_rect.x= x1; + result = (SDL_BlitSurface (texture, &source_rect , dst, &dst_rect) == 0); + } else { // we need to draw multiple times + // draw the first segment + pixels_written = texture->w - texture_x_walker; + source_rect.w = pixels_written; + source_rect.x = texture_x_walker; + dst_rect.x= x1; + result |= (SDL_BlitSurface (texture, &source_rect , dst, &dst_rect) == 0); + write_width = texture->w; + + // now draw the rest + // set the source x to 0 + source_rect.x = 0; + while (pixels_written < w){ + if (write_width >= w - pixels_written) { + write_width = w - pixels_written; + } + source_rect.w = write_width; + dst_rect.x = x1 + pixels_written; + result |= (SDL_BlitSurface (texture,&source_rect , dst, &dst_rect) == 0); + pixels_written += write_width; + } + } + + return result; +} + +/*! +\brief Draws a polygon filled with the given texture (Multi-Threading Capable). + +This operation use internally SDL_BlitSurface for lines of the source texture. It supports +alpha drawing. + +To get the best performance of this operation you need to make sure the texture and the dst surface have the same format +(see http://docs.mandragor.org/files/Common_libs_documentation/SDL/SDL_Documentation_project_en/sdlblitsurface.html). +The last two parameters are optional, but required for multithreaded operation. When set to NULL, uses global static temp array. + +\param dst the destination surface, +\param vx array of x vector components +\param vy array of x vector components +\param n the amount of vectors in the vx and vy array +\param texture the sdl surface to use to fill the polygon +\param texture_dx the offset of the texture relative to the screeen. if you move the polygon 10 pixels +to the left and want the texture to apear the same you need to increase the texture_dx value +\param texture_dy see texture_dx +\param polyInts preallocated temp array storage for vertex sorting (used for multi-threaded operation) +\param polyAllocated flag indicating oif the temp array was allocated (used for multi-threaded operation) + +\returns Returns 0 on success, -1 on failure. +*/ +int texturedPolygonMT(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, + SDL_Surface * texture, int texture_dx, int texture_dy, int **polyInts, int *polyAllocated) +{ + int result; + int i; + int y, xa, xb; + int minx,maxx,miny, maxy; + int x1, y1; + int x2, y2; + int ind1, ind2; + int ints; + int *gfxPrimitivesPolyInts = NULL; + int gfxPrimitivesPolyAllocated = 0; + + /* + * Check visibility of clipping rectangle + */ + if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) { + return(0); + } + + /* + * Sanity check number of edges + */ + if (n < 3) { + return -1; + } + + /* + * Map polygon cache + */ + if ((polyInts==NULL) || (polyAllocated==NULL)) { + /* Use global cache */ + gfxPrimitivesPolyInts = gfxPrimitivesPolyIntsGlobal; + gfxPrimitivesPolyAllocated = gfxPrimitivesPolyAllocatedGlobal; + } else { + /* Use local cache */ + gfxPrimitivesPolyInts = *polyInts; + gfxPrimitivesPolyAllocated = *polyAllocated; + } + + /* + * Allocate temp array, only grow array + */ + if (!gfxPrimitivesPolyAllocated) { + gfxPrimitivesPolyInts = (int *) malloc(sizeof(int) * n); + gfxPrimitivesPolyAllocated = n; + } else { + if (gfxPrimitivesPolyAllocated < n) { + gfxPrimitivesPolyInts = (int *) realloc(gfxPrimitivesPolyInts, sizeof(int) * n); + gfxPrimitivesPolyAllocated = n; + } + } + + /* + * Check temp array + */ + if (gfxPrimitivesPolyInts==NULL) { + gfxPrimitivesPolyAllocated = 0; + } + + /* + * Update cache variables + */ + if ((polyInts==NULL) || (polyAllocated==NULL)) { + gfxPrimitivesPolyIntsGlobal = gfxPrimitivesPolyInts; + gfxPrimitivesPolyAllocatedGlobal = gfxPrimitivesPolyAllocated; + } else { + *polyInts = gfxPrimitivesPolyInts; + *polyAllocated = gfxPrimitivesPolyAllocated; + } + + /* + * Check temp array again + */ + if (gfxPrimitivesPolyInts==NULL) { + return(-1); + } + + /* + * Determine X,Y minima,maxima + */ + miny = vy[0]; + maxy = vy[0]; + minx = vx[0]; + maxx = vx[0]; + for (i = 1; (i < n); i++) { + if (vy[i] < miny) { + miny = vy[i]; + } else if (vy[i] > maxy) { + maxy = vy[i]; + } + if (vx[i] < minx) { + minx = vx[i]; + } else if (vx[i] > maxx) { + maxx = vx[i]; + } + } + if (maxx <0 || minx > dst->w){ + return -1; + } + if (maxy <0 || miny > dst->h){ + return -1; + } + + /* + * Draw, scanning y + */ + result = 0; + for (y = miny; (y <= maxy); y++) { + ints = 0; + for (i = 0; (i < n); i++) { + if (!i) { + ind1 = n - 1; + ind2 = 0; + } else { + ind1 = i - 1; + ind2 = i; + } + y1 = vy[ind1]; + y2 = vy[ind2]; + if (y1 < y2) { + x1 = vx[ind1]; + x2 = vx[ind2]; + } else if (y1 > y2) { + y2 = vy[ind1]; + y1 = vy[ind2]; + x2 = vx[ind1]; + x1 = vx[ind2]; + } else { + continue; + } + if ( ((y >= y1) && (y < y2)) || ((y == maxy) && (y > y1) && (y <= y2)) ) { + gfxPrimitivesPolyInts[ints++] = ((65536 * (y - y1)) / (y2 - y1)) * (x2 - x1) + (65536 * x1); + } + } + + qsort(gfxPrimitivesPolyInts, ints, sizeof(int), _gfxPrimitivesCompareInt); + + for (i = 0; (i < ints); i += 2) { + xa = gfxPrimitivesPolyInts[i] + 1; + xa = (xa >> 16) + ((xa & 32768) >> 15); + xb = gfxPrimitivesPolyInts[i+1] - 1; + xb = (xb >> 16) + ((xb & 32768) >> 15); + result |= _HLineTextured(dst, xa, xb, y, texture, texture_dx, texture_dy); + } + } + + return (result); +} + +/*! +\brief Draws a polygon filled with the given texture. + +This standard version is calling multithreaded versions with NULL cache parameters. + +\param dst the destination surface, +\param vx array of x vector components +\param vy array of x vector components +\param n the amount of vectors in the vx and vy array +\param texture the sdl surface to use to fill the polygon +\param texture_dx the offset of the texture relative to the screeen. if you move the polygon 10 pixels +to the left and want the texture to apear the same you need to increase the texture_dx value +\param texture_dy see texture_dx + +\returns Returns 0 on success, -1 on failure. +*/ +int texturedPolygon(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, SDL_Surface *texture, int texture_dx, int texture_dy) +{ + /* + * Draw + */ + return (texturedPolygonMT(dst, vx, vy, n, texture, texture_dx, texture_dy, NULL, NULL)); +} + + +/* ---- Character */ + +/*! +\brief Global cache for NxM pixel font surfaces created at runtime. +*/ +static SDL_Surface *gfxPrimitivesFont[256]; + +/*! +\brief Global cache of the color used for the font surfaces created at runtime. +*/ +static Uint32 gfxPrimitivesFontColor[256]; + +/*! +\brief Pointer to the current font data. Default is a 8x8 pixel internal font. +*/ +static const unsigned char *currentFontdata = gfxPrimitivesFontdata; + +/*! +\brief Width of the current font. Default is 8. +*/ +static Uint32 charWidth = 8; + +/*! +\brief Height of the current font. Default is 8. +*/ +static Uint32 charHeight = 8; + +/*! +\brief Width for rendering. Autocalculated. +*/ +static Uint32 charWidthLocal = 8; + +/*! +\brief Height for rendering. Autocalculated. +*/ +static Uint32 charHeightLocal = 8; + +/*! +\brief Pitch of the current font in bytes. Default is 1. +*/ +static Uint32 charPitch = 1; + +/*! +\brief Characters 90deg clockwise rotations. Default is 0. Max is 3. +*/ +static Uint32 charRotation = 0; + +/*! +\brief Character data size in bytes of the current font. Default is 8. +*/ +static Uint32 charSize = 8; + +/*! +\brief Sets or resets the current global font data. + +The font data array is organized in follows: +[fontdata] = [character 0][character 1]...[character 255] where +[character n] = [byte 1 row 1][byte 2 row 1]...[byte {pitch} row 1][byte 1 row 2] ...[byte {pitch} row height] where +[byte n] = [bit 0]...[bit 7] where +[bit n] = [0 for transparent pixel|1 for colored pixel] + +\param fontdata Pointer to array of font data. Set to NULL, to reset global font to the default 8x8 font. +\param cw Width of character in bytes. Ignored if fontdata==NULL. +\param ch Height of character in bytes. Ignored if fontdata==NULL. +*/ +void gfxPrimitivesSetFont(const void *fontdata, Uint32 cw, Uint32 ch) +{ + int i; + + if ((fontdata) && (cw) && (ch)) { + currentFontdata = fontdata; + charWidth = cw; + charHeight = ch; + } else { + currentFontdata = gfxPrimitivesFontdata; + charWidth = 8; + charHeight = 8; + } + + charPitch = (charWidth+7)/8; + charSize = charPitch * charHeight; + + /* Maybe flip width/height for rendering */ + if ((charRotation==1) || (charRotation==3)) + { + charWidthLocal = charHeight; + charHeightLocal = charWidth; + } + else + { + charWidthLocal = charWidth; + charHeightLocal = charHeight; + } + + /* Clear character cache */ + for (i = 0; i < 256; i++) { + if (gfxPrimitivesFont[i]) { + SDL_FreeSurface(gfxPrimitivesFont[i]); + gfxPrimitivesFont[i] = NULL; + } + } +} + +/*! +\brief Sets current global font character rotation steps. + +Default is 0 (no rotation). 1 = 90deg clockwise. 2 = 180deg clockwise. 3 = 270deg clockwise. +Changing the rotation, will reset the character cache. + +\param rotation Number of 90deg clockwise steps to rotate +*/ +void gfxPrimitivesSetFontRotation(Uint32 rotation) +{ + int i; + + rotation = rotation & 3; + if (charRotation != rotation) + { + /* Store rotation */ + charRotation = rotation; + + /* Maybe flip width/height for rendering */ + if ((charRotation==1) || (charRotation==3)) + { + charWidthLocal = charHeight; + charHeightLocal = charWidth; + } + else + { + charWidthLocal = charWidth; + charHeightLocal = charHeight; + } + + /* Clear character cache */ + for (i = 0; i < 256; i++) { + if (gfxPrimitivesFont[i]) { + SDL_FreeSurface(gfxPrimitivesFont[i]); + gfxPrimitivesFont[i] = NULL; + } + } + } +} + +/*! +\brief Draw a character of the currently set font. + +On first call for a particular character and color combination, the function needs to +generate the character surface (slower. Subsequent calls blit a cached surface (fast). +Uses alpha blending if A<255 in color. + +\param dst The surface to draw on. +\param x X (horizontal) coordinate of the upper left corner of the character. +\param y Y (vertical) coordinate of the upper left corner of the character. +\param c The character to draw. +\param color The color value of the character to draw (0xRRGGBBAA). + +\returns Returns 0 on success, -1 on failure. +*/ +int characterColor(SDL_Surface * dst, Sint16 x, Sint16 y, char c, Uint32 color) +{ + Sint16 left, right, top, bottom; + Sint16 x1, y1, x2, y2; + SDL_Rect srect; + SDL_Rect drect; + int result; + Uint32 ix, iy; + const unsigned char *charpos; + Uint8 *curpos; + int forced_redraw; + Uint8 patt, mask; + Uint8 *linepos; + Uint32 pitch; + SDL_Surface *rotatedCharacter; + Uint32 ci; + + /* + * Check visibility of clipping rectangle + */ + if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) { + return(0); + } + + /* + * Get text and clipping boundary and + * test if bounding box of character is visible + */ + + left = dst->clip_rect.x; + x2 = x + charWidthLocal; + if (x2clip_rect.x + dst->clip_rect.w - 1; + x1 = x; + if (x1>right) { + return(0); + } + top = dst->clip_rect.y; + y2 = y + charHeightLocal; + if (y2clip_rect.y + dst->clip_rect.h - 1; + y1 = y; + if (y1>bottom) { + return(0); + } + + /* + * Setup source rectangle + */ + srect.x = 0; + srect.y = 0; + srect.w = charWidthLocal; + srect.h = charHeightLocal; + + /* + * Setup destination rectangle + */ + drect.x = x; + drect.y = y; + drect.w = charWidthLocal; + drect.h = charHeightLocal; + + /* Character index in cache */ + ci = (unsigned char) c; + + /* + * Create new charWidth x charHeight bitmap surface if not already present. + * Might get rotated later. + */ + if (gfxPrimitivesFont[ci] == NULL) { + gfxPrimitivesFont[ci] = + SDL_CreateRGBSurface(SDL_SWSURFACE | SDL_HWSURFACE | SDL_SRCALPHA, + charWidth, charHeight, 32, + 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF); + /* + * Check pointer + */ + if (gfxPrimitivesFont[ci] == NULL) { + return (-1); + } + /* + * Definitely redraw + */ + forced_redraw = 1; + } else { + forced_redraw = 0; + } + + /* + * Check if color has changed + */ + if ((gfxPrimitivesFontColor[ci] != color) || (forced_redraw)) { + /* + * Redraw character + */ + SDL_SetAlpha(gfxPrimitivesFont[ci], SDL_SRCALPHA, 255); + gfxPrimitivesFontColor[ci] = color; + + /* Lock font-surface */ + if (SDL_LockSurface(gfxPrimitivesFont[ci]) != 0) + return (-1); + + /* + * Variable setup + */ + charpos = currentFontdata + ci * charSize; + linepos = (Uint8 *) gfxPrimitivesFont[ci]->pixels; + pitch = gfxPrimitivesFont[ci]->pitch; + + /* + * Drawing loop + */ + patt = 0; + for (iy = 0; iy < charHeight; iy++) { + mask = 0x00; + curpos = linepos; + for (ix = 0; ix < charWidth; ix++) { + if (!(mask >>= 1)) { + patt = *charpos++; + mask = 0x80; + } + + if (patt & mask) + *(Uint32 *)curpos = color; + else + *(Uint32 *)curpos = 0; + curpos += 4; + } + linepos += pitch; + } + + /* Unlock font-surface */ + SDL_UnlockSurface(gfxPrimitivesFont[ci]); + + /* Maybe rotate and replace cached image */ + if (charRotation>0) + { + rotatedCharacter = rotateSurface90Degrees(gfxPrimitivesFont[ci], charRotation); + SDL_FreeSurface(gfxPrimitivesFont[ci]); + gfxPrimitivesFont[ci] = rotatedCharacter; + } + } + + /* + * Draw bitmap onto destination surface + */ + result = SDL_BlitSurface(gfxPrimitivesFont[ci], &srect, dst, &drect); + + return (result); +} + +/*! +\brief Draw a character of the currently set font. + +\param dst The surface to draw on. +\param x X (horizontal) coordinate of the upper left corner of the character. +\param y Y (vertical) coordinate of the upper left corner of the character. +\param c The character to draw. +\param r The red value of the character to draw. +\param g The green value of the character to draw. +\param b The blue value of the character to draw. +\param a The alpha value of the character to draw. + +\returns Returns 0 on success, -1 on failure. +*/ +int characterRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, char c, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + /* + * Draw + */ + return (characterColor(dst, x, y, c, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a)); +} + +/*! +\brief Draw a string in the currently set font. + +The spacing between consequtive characters in the string is the fixed number of pixels +of the character width of the current global font. + +\param dst The surface to draw on. +\param x X (horizontal) coordinate of the upper left corner of the string. +\param y Y (vertical) coordinate of the upper left corner of the string. +\param s The string to draw. +\param color The color value of the string to draw (0xRRGGBBAA). + +\returns Returns 0 on success, -1 on failure. +*/ +int stringColor(SDL_Surface * dst, Sint16 x, Sint16 y, const char *s, Uint32 color) +{ + int result = 0; + Sint16 curx = x; + Sint16 cury = y; + const char *curchar = s; + + while (*curchar && !result) { + result |= characterColor(dst, curx, cury, *curchar, color); + switch (charRotation) + { + case 0: + curx += charWidthLocal; + break; + case 2: + curx -= charWidthLocal; + break; + case 1: + cury += charHeightLocal; + break; + case 3: + cury -= charHeightLocal; + break; + } + curchar++; + } + + return (result); +} + +/*! +\brief Draw a string in the currently set font. + +\param dst The surface to draw on. +\param x X (horizontal) coordinate of the upper left corner of the string. +\param y Y (vertical) coordinate of the upper left corner of the string. +\param s The string to draw. +\param r The red value of the string to draw. +\param g The green value of the string to draw. +\param b The blue value of the string to draw. +\param a The alpha value of the string to draw. + +\returns Returns 0 on success, -1 on failure. +*/ +int stringRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, const char *s, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + /* + * Draw + */ + return (stringColor(dst, x, y, s, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a)); +} + +/* ---- Bezier curve */ + +/*! +\brief Internal function to calculate bezier interpolator of data array with ndata values at position 't'. + +\param data Array of values. +\param ndata Size of array. +\param t Position for which to calculate interpolated value. t should be between [0, ndata]. + +\returns Interpolated value at position t, value[0] when t<0, value[n-1] when t>n. +*/ +double _evaluateBezier (double *data, int ndata, double t) +{ + double mu, result; + int n,k,kn,nn,nkn; + double blend,muk,munk; + + /* Sanity check bounds */ + if (t<0.0) { + return(data[0]); + } + if (t>=(double)ndata) { + return(data[ndata-1]); + } + + /* Adjust t to the range 0.0 to 1.0 */ + mu=t/(double)ndata; + + /* Calculate interpolate */ + n=ndata-1; + result=0.0; + muk = 1; + munk = pow(1-mu,(double)n); + for (k=0;k<=n;k++) { + nn = n; + kn = k; + nkn = n - k; + blend = muk * munk; + muk *= mu; + munk /= (1-mu); + while (nn >= 1) { + blend *= nn; + nn--; + if (kn > 1) { + blend /= (double)kn; + kn--; + } + if (nkn > 1) { + blend /= (double)nkn; + nkn--; + } + } + result += data[k] * blend; + } + + return (result); +} + +/*! +\brief Draw a bezier curve with alpha blending. + +\param dst The surface to draw on. +\param vx Vertex array containing X coordinates of the points of the bezier curve. +\param vy Vertex array containing Y coordinates of the points of the bezier curve. +\param n Number of points in the vertex array. Minimum number is 3. +\param s Number of steps for the interpolation. Minimum number is 2. +\param color The color value of the bezier curve to draw (0xRRGGBBAA). + +\returns Returns 0 on success, -1 on failure. +*/ +int bezierColor(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, int s, Uint32 color) +{ + int result; + int i; + double *x, *y, t, stepsize; + Sint16 x1, y1, x2, y2; + + /* + * Sanity check + */ + if (n < 3) { + return (-1); + } + if (s < 2) { + return (-1); + } + + /* + * Variable setup + */ + stepsize=(double)1.0/(double)s; + + /* Transfer vertices into float arrays */ + if ((x=(double *)malloc(sizeof(double)*(n+1)))==NULL) { + return(-1); + } + if ((y=(double *)malloc(sizeof(double)*(n+1)))==NULL) { + free(x); + return(-1); + } + for (i=0; ix = x1; + b->y = y1; + + /* dx = abs(x2-x1), s1 = sign(x2-x1) */ + if ((b->dx = x2 - x1) != 0) { + if (b->dx < 0) { + b->dx = -b->dx; + b->s1 = -1; + } else { + b->s1 = 1; + } + } else { + b->s1 = 0; + } + + /* dy = abs(y2-y1), s2 = sign(y2-y1) */ + if ((b->dy = y2 - y1) != 0) { + if (b->dy < 0) { + b->dy = -b->dy; + b->s2 = -1; + } else { + b->s2 = 1; + } + } else { + b->s2 = 0; + } + + if (b->dy > b->dx) { + temp = b->dx; + b->dx = b->dy; + b->dy = temp; + b->swapdir = 1; + } else { + b->swapdir = 0; + } + + b->count = b->dx; + b->dy <<= 1; + b->error = b->dy - b->dx; + b->dx <<= 1; + + return(0); +} + + +/*! +\brief Internal function to move Bresenham line iterator to the next position. + +Maybe updates the x and y coordinates of the iterator struct. + +\param b Pointer to struct for bresenham line drawing state. + +\returns Returns 0 on success, 1 if last point was reached, 2 if moving past end-of-line, -1 on failure. +*/ +int _bresenhamIterate(SDL_gfxBresenhamIterator *b) +{ + if (b==NULL) { + return (-1); + } + + /* last point check */ + if (b->count <= 0) { + return (2); + } + + while (b->error >= 0) { + if (b->swapdir) { + b->x += b->s1; + } else { + b->y += b->s2; + } + + b->error -= b->dx; + } + + if (b->swapdir) { + b->y += b->s2; + } else { + b->x += b->s1; + } + + b->error += b->dy; + b->count--; + + /* count==0 indicates "end-of-line" */ + return ((b->count) ? 0 : 1); +} + + +/*! +\brief Internal function to to draw parallel lines with Murphy algorithm. + +\param m Pointer to struct for murphy iterator. +\param x X coordinate of point. +\param y Y coordinate of point. +\param d1 Direction square/diagonal. +*/ +void _murphyParaline(SDL_gfxMurphyIterator *m, Sint16 x, Sint16 y, int d1) +{ + int p; + d1 = -d1; + + /* + * Lock the surface + */ + if (SDL_MUSTLOCK(m->dst)) { + SDL_LockSurface(m->dst); + } + + for (p = 0; p <= m->u; p++) { + + pixelColorNolock(m->dst, x, y, m->color); + + if (d1 <= m->kt) { + if (m->oct2 == 0) { + x++; + } else { + if (m->quad4 == 0) { + y++; + } else { + y--; + } + } + d1 += m->kv; + } else { + x++; + if (m->quad4 == 0) { + y++; + } else { + y--; + } + d1 += m->kd; + } + } + + /* Unlock surface */ + if (SDL_MUSTLOCK(m->dst)) { + SDL_UnlockSurface(m->dst); + } + + m->tempx = x; + m->tempy = y; +} + +/*! +\brief Internal function to to draw one iteration of the Murphy algorithm. + +\param m Pointer to struct for murphy iterator. +\param miter Iteration count. +\param ml1bx X coordinate of a point. +\param ml1by Y coordinate of a point. +\param ml2bx X coordinate of a point. +\param ml2by Y coordinate of a point. +\param ml1x X coordinate of a point. +\param ml1y Y coordinate of a point. +\param ml2x X coordinate of a point. +\param ml2y Y coordinate of a point. + +*/ +void _murphyIteration(SDL_gfxMurphyIterator *m, Uint8 miter, + Uint16 ml1bx, Uint16 ml1by, Uint16 ml2bx, Uint16 ml2by, + Uint16 ml1x, Uint16 ml1y, Uint16 ml2x, Uint16 ml2y) +{ + int atemp1, atemp2; + int ftmp1, ftmp2; + Uint16 m1x, m1y, m2x, m2y; + Uint16 fix, fiy, lax, lay, curx, cury; + Uint16 px[4], py[4]; + SDL_gfxBresenhamIterator b; + + if (miter > 1) { + if (m->first1x != -32768) { + fix = (m->first1x + m->first2x) / 2; + fiy = (m->first1y + m->first2y) / 2; + lax = (m->last1x + m->last2x) / 2; + lay = (m->last1y + m->last2y) / 2; + curx = (ml1x + ml2x) / 2; + cury = (ml1y + ml2y) / 2; + + atemp1 = (fix - curx); + atemp2 = (fiy - cury); + ftmp1 = atemp1 * atemp1 + atemp2 * atemp2; + atemp1 = (lax - curx); + atemp2 = (lay - cury); + ftmp2 = atemp1 * atemp1 + atemp2 * atemp2; + + if (ftmp1 <= ftmp2) { + m1x = m->first1x; + m1y = m->first1y; + m2x = m->first2x; + m2y = m->first2y; + } else { + m1x = m->last1x; + m1y = m->last1y; + m2x = m->last2x; + m2y = m->last2y; + } + + atemp1 = (m2x - ml2x); + atemp2 = (m2y - ml2y); + ftmp1 = atemp1 * atemp1 + atemp2 * atemp2; + atemp1 = (m2x - ml2bx); + atemp2 = (m2y - ml2by); + ftmp2 = atemp1 * atemp1 + atemp2 * atemp2; + + if (ftmp2 >= ftmp1) { + ftmp1 = ml2bx; + ftmp2 = ml2by; + ml2bx = ml2x; + ml2by = ml2y; + ml2x = ftmp1; + ml2y = ftmp2; + ftmp1 = ml1bx; + ftmp2 = ml1by; + ml1bx = ml1x; + ml1by = ml1y; + ml1x = ftmp1; + ml1y = ftmp2; + } + + /* + * Lock the surface + */ + if (SDL_MUSTLOCK(m->dst)) { + SDL_LockSurface(m->dst); + } + + _bresenhamInitialize(&b, m2x, m2y, m1x, m1y); + do { + pixelColorNolock(m->dst, b.x, b.y, m->color); + } while (_bresenhamIterate(&b)==0); + + _bresenhamInitialize(&b, m1x, m1y, ml1bx, ml1by); + do { + pixelColorNolock(m->dst, b.x, b.y, m->color); + } while (_bresenhamIterate(&b)==0); + + _bresenhamInitialize(&b, ml1bx, ml1by, ml2bx, ml2by); + do { + pixelColorNolock(m->dst, b.x, b.y, m->color); + } while (_bresenhamIterate(&b)==0); + + _bresenhamInitialize(&b, ml2bx, ml2by, m2x, m2y); + do { + pixelColorNolock(m->dst, b.x, b.y, m->color); + } while (_bresenhamIterate(&b)==0); + + /* Unlock surface */ + if (SDL_MUSTLOCK(m->dst)) { + SDL_UnlockSurface(m->dst); + } + + px[0] = m1x; + px[1] = m2x; + px[2] = ml1bx; + px[3] = ml2bx; + py[0] = m1y; + py[1] = m2y; + py[2] = ml1by; + py[3] = ml2by; + polygonColor(m->dst, px, py, 4, m->color); + } + } + + m->last1x = ml1x; + m->last1y = ml1y; + m->last2x = ml2x; + m->last2y = ml2y; + m->first1x = ml1bx; + m->first1y = ml1by; + m->first2x = ml2bx; + m->first2y = ml2by; +} + + +#define HYPOT(x,y) sqrt((double)(x)*(double)(x)+(double)(y)*(double)(y)) + +/*! +\brief Internal function to to draw wide lines with Murphy algorithm. + +Draws lines parallel to ideal line. + +\param m Pointer to struct for murphy iterator. +\param x1 X coordinate of first point. +\param y1 Y coordinate of first point. +\param x2 X coordinate of second point. +\param y2 Y coordinate of second point. +\param width Width of line. +\param miter Iteration count. + +*/ +void _murphyWideline(SDL_gfxMurphyIterator *m, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 width, Uint8 miter) +{ + float offset = width / 2.f; + + Sint16 temp; + Sint16 ptx, pty, ptxx, ptxy, ml1x, ml1y, ml2x, ml2y, ml1bx, ml1by, ml2bx, ml2by; + + int d0, d1; /* difference terms d0=perpendicular to line, d1=along line */ + + int q; /* pel counter,q=perpendicular to line */ + int tmp; + + int dd; /* distance along line */ + int tk; /* thickness threshold */ + double ang; /* angle for initial point calculation */ + double sang, cang; + + /* Initialisation */ + m->u = x2 - x1; /* delta x */ + m->v = y2 - y1; /* delta y */ + + if (m->u < 0) { /* swap to make sure we are in quadrants 1 or 4 */ + temp = x1; + x1 = x2; + x2 = temp; + temp = y1; + y1 = y2; + y1 = temp; + m->u *= -1; + m->v *= -1; + } + + if (m->v < 0) { /* swap to 1st quadrant and flag */ + m->v *= -1; + m->quad4 = 1; + } else { + m->quad4 = 0; + } + + if (m->v > m->u) { /* swap things if in 2 octant */ + tmp = m->u; + m->u = m->v; + m->v = tmp; + m->oct2 = 1; + } else { + m->oct2 = 0; + } + + m->ku = m->u + m->u; /* change in l for square shift */ + m->kv = m->v + m->v; /* change in d for square shift */ + m->kd = m->kv - m->ku; /* change in d for diagonal shift */ + m->kt = m->u - m->kv; /* diag/square decision threshold */ + + d0 = 0; + d1 = 0; + dd = 0; + + ang = atan((double) m->v / (double) m->u); /* calc new initial point - offset both sides of ideal */ + sang = sin(ang); + cang = cos(ang); + + if (m->oct2 == 0) { + ptx = x1 + (Sint16)lrint(offset * sang); + if (m->quad4 == 0) { + pty = y1 - (Sint16)lrint(offset * cang); + } else { + pty = y1 + (Sint16)lrint(offset * cang); + } + } else { + ptx = x1 - (Sint16)lrint(offset * cang); + if (m->quad4 == 0) { + pty = y1 + (Sint16)lrint(offset * sang); + } else { + pty = y1 - (Sint16)lrint(offset * sang); + } + } + + /* used here for constant thickness line */ + tk = (int) (4. * HYPOT(ptx - x1, pty - y1) * HYPOT(m->u, m->v)); + + if (miter == 0) { + m->first1x = -32768; + m->first1y = -32768; + m->first2x = -32768; + m->first2y = -32768; + m->last1x = -32768; + m->last1y = -32768; + m->last2x = -32768; + m->last2y = -32768; + } + ptxx = ptx; + ptxy = pty; + + for (q = 0; dd <= tk; q++) { /* outer loop, stepping perpendicular to line */ + + _murphyParaline(m, ptx, pty, d1); /* call to inner loop - right edge */ + if (q == 0) { + ml1x = ptx; + ml1y = pty; + ml1bx = m->tempx; + ml1by = m->tempy; + } else { + ml2x = ptx; + ml2y = pty; + ml2bx = m->tempx; + ml2by = m->tempy; + } + if (d0 < m->kt) { /* square move */ + if (m->oct2 == 0) { + if (m->quad4 == 0) { + pty++; + } else { + pty--; + } + } else { + ptx++; + } + } else { /* diagonal move */ + dd += m->kv; + d0 -= m->ku; + if (d1 < m->kt) { /* normal diagonal */ + if (m->oct2 == 0) { + ptx--; + if (m->quad4 == 0) { + pty++; + } else { + pty--; + } + } else { + ptx++; + if (m->quad4 == 0) { + pty--; + } else { + pty++; + } + } + d1 += m->kv; + } else { /* double square move, extra parallel line */ + if (m->oct2 == 0) { + ptx--; + } else { + if (m->quad4 == 0) { + pty--; + } else { + pty++; + } + } + d1 += m->kd; + if (dd > tk) { + _murphyIteration(m, miter, ml1bx, ml1by, ml2bx, ml2by, ml1x, ml1y, ml2x, ml2y); + return; /* breakout on the extra line */ + } + _murphyParaline(m, ptx, pty, d1); + if (m->oct2 == 0) { + if (m->quad4 == 0) { + pty++; + } else { + + pty--; + } + } else { + ptx++; + } + } + } + dd += m->ku; + d0 += m->kv; + } + + _murphyIteration(m, miter, ml1bx, ml1by, ml2bx, ml2by, ml1x, ml1y, ml2x, ml2y); +} + + +/*! +\brief Draw a thick line with alpha blending. + +\param dst The surface to draw on. +\param x1 X coordinate of the first point of the line. +\param y1 Y coordinate of the first point of the line. +\param x2 X coordinate of the second point of the line. +\param y2 Y coordinate of the second point of the line. +\param width Width of the line in pixels. Must be >0. +\param color The color value of the line to draw (0xRRGGBBAA). + +\returns Returns 0 on success, -1 on failure. +*/ +int thickLineColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 width, Uint32 color) +{ + SDL_gfxMurphyIterator m; + + if (dst == NULL) return -1; + if (width < 1) return -1; + + m.dst = dst; + m.color = color; + + _murphyWideline(&m, x1, y1, x2, y2, width, 0); + _murphyWideline(&m, x1, y1, x2, y2, width, 1); + + return(0); +} + +/*! +\brief Draw a thick line with alpha blending. + +\param dst The surface to draw on. +\param x1 X coordinate of the first point of the line. +\param y1 Y coordinate of the first point of the line. +\param x2 X coordinate of the second point of the line. +\param y2 Y coordinate of the second point of the line. +\param width Width of the line in pixels. Must be >0. +\param r The red value of the character to draw. +\param g The green value of the character to draw. +\param b The blue value of the character to draw. +\param a The alpha value of the character to draw. + +\returns Returns 0 on success, -1 on failure. +*/ +int thickLineRGBA(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 width, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + return (thickLineColor(dst, x1, y1, x2, y2, width, + ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a)); +} diff --git a/engines/vileVN/external/SDL/gfx/SDL_gfxPrimitives.h b/engines/vileVN/external/SDL/gfx/SDL_gfxPrimitives.h new file mode 100644 index 0000000000..62f3b70e7f --- /dev/null +++ b/engines/vileVN/external/SDL/gfx/SDL_gfxPrimitives.h @@ -0,0 +1,225 @@ +/* + +SDL_gfxPrimitives: graphics primitives for SDL + +LGPL (c) A. Schiffler + +*/ + +#ifndef _SDL_gfxPrimitives_h +#define _SDL_gfxPrimitives_h + +#include +#ifndef M_PI +#define M_PI 3.1415926535897932384626433832795 +#endif + +#include "SDL.h" + +/* Set up for C function definitions, even when using C++ */ +#ifdef __cplusplus +extern "C" { +#endif + + /* ----- Versioning */ + +#define SDL_GFXPRIMITIVES_MAJOR 2 +#define SDL_GFXPRIMITIVES_MINOR 0 +#define SDL_GFXPRIMITIVES_MICRO 22 + + + /* ---- Function Prototypes */ + +#if defined(WIN32) || defined(WIN64) +# if defined(DLL_EXPORT) && !defined(LIBSDL_GFX_DLL_IMPORT) +# define SDL_GFXPRIMITIVES_SCOPE __declspec(dllexport) +# else +# ifdef LIBSDL_GFX_DLL_IMPORT +# define SDL_GFXPRIMITIVES_SCOPE __declspec(dllimport) +# endif +# endif +#endif +#ifndef SDL_GFXPRIMITIVES_SCOPE +# define SDL_GFXPRIMITIVES_SCOPE extern +#endif + + /* Note: all ___Color routines expect the color to be in format 0xRRGGBBAA */ + + /* Pixel */ + + SDL_GFXPRIMITIVES_SCOPE int pixelColor(SDL_Surface * dst, Sint16 x, Sint16 y, Uint32 color); + SDL_GFXPRIMITIVES_SCOPE int pixelRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Uint8 r, Uint8 g, Uint8 b, Uint8 a); + + /* Horizontal line */ + + SDL_GFXPRIMITIVES_SCOPE int hlineColor(SDL_Surface * dst, Sint16 x1, Sint16 x2, Sint16 y, Uint32 color); + SDL_GFXPRIMITIVES_SCOPE int hlineRGBA(SDL_Surface * dst, Sint16 x1, Sint16 x2, Sint16 y, Uint8 r, Uint8 g, Uint8 b, Uint8 a); + + /* Vertical line */ + + SDL_GFXPRIMITIVES_SCOPE int vlineColor(SDL_Surface * dst, Sint16 x, Sint16 y1, Sint16 y2, Uint32 color); + SDL_GFXPRIMITIVES_SCOPE int vlineRGBA(SDL_Surface * dst, Sint16 x, Sint16 y1, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a); + + /* Rectangle */ + + SDL_GFXPRIMITIVES_SCOPE int rectangleColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color); + SDL_GFXPRIMITIVES_SCOPE int rectangleRGBA(SDL_Surface * dst, Sint16 x1, Sint16 y1, + Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a); + + /* Rounded-Corner Rectangle */ + + SDL_GFXPRIMITIVES_SCOPE int roundedRectangleColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 rad, Uint32 color); + SDL_GFXPRIMITIVES_SCOPE int roundedRectangleRGBA(SDL_Surface * dst, Sint16 x1, Sint16 y1, + Sint16 x2, Sint16 y2, Sint16 rad, Uint8 r, Uint8 g, Uint8 b, Uint8 a); + + /* Filled rectangle (Box) */ + + SDL_GFXPRIMITIVES_SCOPE int boxColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color); + SDL_GFXPRIMITIVES_SCOPE int boxRGBA(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, + Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a); + + /* Rounded-Corner Filled rectangle (Box) */ + + SDL_GFXPRIMITIVES_SCOPE int roundedBoxColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 rad, Uint32 color); + SDL_GFXPRIMITIVES_SCOPE int roundedBoxRGBA(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, + Sint16 y2, Sint16 rad, Uint8 r, Uint8 g, Uint8 b, Uint8 a); + + /* Line */ + + SDL_GFXPRIMITIVES_SCOPE int lineColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color); + SDL_GFXPRIMITIVES_SCOPE int lineRGBA(SDL_Surface * dst, Sint16 x1, Sint16 y1, + Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a); + + /* AA Line */ + + SDL_GFXPRIMITIVES_SCOPE int aalineColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color); + SDL_GFXPRIMITIVES_SCOPE int aalineRGBA(SDL_Surface * dst, Sint16 x1, Sint16 y1, + Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a); + + /* Thick Line */ + SDL_GFXPRIMITIVES_SCOPE int thickLineColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, + Uint8 width, Uint32 color); + SDL_GFXPRIMITIVES_SCOPE int thickLineRGBA(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, + Uint8 width, Uint8 r, Uint8 g, Uint8 b, Uint8 a); + + /* Circle */ + + SDL_GFXPRIMITIVES_SCOPE int circleColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad, Uint32 color); + SDL_GFXPRIMITIVES_SCOPE int circleRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad, Uint8 r, Uint8 g, Uint8 b, Uint8 a); + + /* Arc */ + + SDL_GFXPRIMITIVES_SCOPE int arcColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad, Sint16 start, Sint16 end, Uint32 color); + SDL_GFXPRIMITIVES_SCOPE int arcRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad, Sint16 start, Sint16 end, + Uint8 r, Uint8 g, Uint8 b, Uint8 a); + + /* AA Circle */ + + SDL_GFXPRIMITIVES_SCOPE int aacircleColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad, Uint32 color); + SDL_GFXPRIMITIVES_SCOPE int aacircleRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, + Sint16 rad, Uint8 r, Uint8 g, Uint8 b, Uint8 a); + + /* Filled Circle */ + + SDL_GFXPRIMITIVES_SCOPE int filledCircleColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 r, Uint32 color); + SDL_GFXPRIMITIVES_SCOPE int filledCircleRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, + Sint16 rad, Uint8 r, Uint8 g, Uint8 b, Uint8 a); + + /* Ellipse */ + + SDL_GFXPRIMITIVES_SCOPE int ellipseColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint32 color); + SDL_GFXPRIMITIVES_SCOPE int ellipseRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, + Sint16 rx, Sint16 ry, Uint8 r, Uint8 g, Uint8 b, Uint8 a); + + /* AA Ellipse */ + + SDL_GFXPRIMITIVES_SCOPE int aaellipseColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint32 color); + SDL_GFXPRIMITIVES_SCOPE int aaellipseRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, + Sint16 rx, Sint16 ry, Uint8 r, Uint8 g, Uint8 b, Uint8 a); + + /* Filled Ellipse */ + + SDL_GFXPRIMITIVES_SCOPE int filledEllipseColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint32 color); + SDL_GFXPRIMITIVES_SCOPE int filledEllipseRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, + Sint16 rx, Sint16 ry, Uint8 r, Uint8 g, Uint8 b, Uint8 a); + + /* Pie */ + + SDL_GFXPRIMITIVES_SCOPE int pieColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad, + Sint16 start, Sint16 end, Uint32 color); + SDL_GFXPRIMITIVES_SCOPE int pieRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad, + Sint16 start, Sint16 end, Uint8 r, Uint8 g, Uint8 b, Uint8 a); + + /* Filled Pie */ + + SDL_GFXPRIMITIVES_SCOPE int filledPieColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad, + Sint16 start, Sint16 end, Uint32 color); + SDL_GFXPRIMITIVES_SCOPE int filledPieRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad, + Sint16 start, Sint16 end, Uint8 r, Uint8 g, Uint8 b, Uint8 a); + + /* Trigon */ + + SDL_GFXPRIMITIVES_SCOPE int trigonColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, Uint32 color); + SDL_GFXPRIMITIVES_SCOPE int trigonRGBA(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, + Uint8 r, Uint8 g, Uint8 b, Uint8 a); + + /* AA-Trigon */ + + SDL_GFXPRIMITIVES_SCOPE int aatrigonColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, Uint32 color); + SDL_GFXPRIMITIVES_SCOPE int aatrigonRGBA(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, + Uint8 r, Uint8 g, Uint8 b, Uint8 a); + + /* Filled Trigon */ + + SDL_GFXPRIMITIVES_SCOPE int filledTrigonColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, Uint32 color); + SDL_GFXPRIMITIVES_SCOPE int filledTrigonRGBA(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, + Uint8 r, Uint8 g, Uint8 b, Uint8 a); + + /* Polygon */ + + SDL_GFXPRIMITIVES_SCOPE int polygonColor(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, Uint32 color); + SDL_GFXPRIMITIVES_SCOPE int polygonRGBA(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, + int n, Uint8 r, Uint8 g, Uint8 b, Uint8 a); + + /* AA-Polygon */ + + SDL_GFXPRIMITIVES_SCOPE int aapolygonColor(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, Uint32 color); + SDL_GFXPRIMITIVES_SCOPE int aapolygonRGBA(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, + int n, Uint8 r, Uint8 g, Uint8 b, Uint8 a); + + /* Filled Polygon */ + + SDL_GFXPRIMITIVES_SCOPE int filledPolygonColor(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, Uint32 color); + SDL_GFXPRIMITIVES_SCOPE int filledPolygonRGBA(SDL_Surface * dst, const Sint16 * vx, + const Sint16 * vy, int n, Uint8 r, Uint8 g, Uint8 b, Uint8 a); + SDL_GFXPRIMITIVES_SCOPE int texturedPolygon(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, SDL_Surface * texture,int texture_dx,int texture_dy); + + /* (Note: These MT versions are required for multi-threaded operation.) */ + + SDL_GFXPRIMITIVES_SCOPE int filledPolygonColorMT(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, Uint32 color, int **polyInts, int *polyAllocated); + SDL_GFXPRIMITIVES_SCOPE int filledPolygonRGBAMT(SDL_Surface * dst, const Sint16 * vx, + const Sint16 * vy, int n, Uint8 r, Uint8 g, Uint8 b, Uint8 a, + int **polyInts, int *polyAllocated); + SDL_GFXPRIMITIVES_SCOPE int texturedPolygonMT(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, SDL_Surface * texture,int texture_dx,int texture_dy, int **polyInts, int *polyAllocated); + + /* Bezier */ + + SDL_GFXPRIMITIVES_SCOPE int bezierColor(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, int s, Uint32 color); + SDL_GFXPRIMITIVES_SCOPE int bezierRGBA(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, + int n, int s, Uint8 r, Uint8 g, Uint8 b, Uint8 a); + + /* Characters/Strings */ + + SDL_GFXPRIMITIVES_SCOPE void gfxPrimitivesSetFont(const void *fontdata, Uint32 cw, Uint32 ch); + SDL_GFXPRIMITIVES_SCOPE void gfxPrimitivesSetFontRotation(Uint32 rotation); + SDL_GFXPRIMITIVES_SCOPE int characterColor(SDL_Surface * dst, Sint16 x, Sint16 y, char c, Uint32 color); + SDL_GFXPRIMITIVES_SCOPE int characterRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, char c, Uint8 r, Uint8 g, Uint8 b, Uint8 a); + SDL_GFXPRIMITIVES_SCOPE int stringColor(SDL_Surface * dst, Sint16 x, Sint16 y, const char *s, Uint32 color); + SDL_GFXPRIMITIVES_SCOPE int stringRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, const char *s, Uint8 r, Uint8 g, Uint8 b, Uint8 a); + + /* Ends C function definitions when using C++ */ +#ifdef __cplusplus +} +#endif + +#endif /* _SDL_gfxPrimitives_h */ diff --git a/engines/vileVN/external/SDL/gfx/SDL_imageFilter.c b/engines/vileVN/external/SDL/gfx/SDL_imageFilter.c new file mode 100644 index 0000000000..f42acfb33f --- /dev/null +++ b/engines/vileVN/external/SDL/gfx/SDL_imageFilter.c @@ -0,0 +1,7556 @@ +/* + +SDL_imageFilter - bytes-image "filter" routines. +(Uses inline x86 MMX or ASM optimizations if available and enabled.) + +LGPL (c) A. Schiffler + +Note: Most of the MMX code is based on published routines +by Vladimir Kravtchenko at vk@cs.ubc.ca - credits go to +him for his work. + +*/ + +#include +#include +#include + +#include "SDL_imageFilter.h" + +/*! +\brief Swaps the byte order in a 32bit integer (LSB becomes MSB, etc.). +*/ +#define SWAP_32(x) (((x) >> 24) | (((x) & 0x00ff0000) >> 8) | (((x) & 0x0000ff00) << 8) | ((x) << 24)) + +/* ------ Static variables ----- */ + +/*! +\brief Static state which enables the use of the MMX routines. Enabled by default +*/ +static int SDL_imageFilterUseMMX = 1; + +/* Detect GCC */ +#if defined(__GNUC__) +#define GCC__ +#endif + +/*! +\brief Internal function returning the CPU flags. + +\returns Flags of system CPU. +*/ +unsigned int _cpuFlags() +{ + int flags = 0; + +#ifdef USE_MMX +#if !defined(GCC__) + __asm + { + pusha + mov eax, 1 + cpuid /* get CPU ID flag */ + mov flags,edx /* move result to mmx_bit */ + popa + } +#else + asm volatile ("pusha \n\t" "mov %1, %%eax \n\t" /* request feature flag */ + "cpuid \n\t" /* get CPU ID flag */ + "mov %%edx, %0 \n\t" /* move result to mmx_bit */ + "popa \n\t":"=m" (flags) /* %0 */ + :"i"(0x00000001) /* %1 */ + ); +#endif +#endif + + return (flags); +} + +/*! +\brief MMX detection routine (with override flag). + +\returns 1 of MMX was detected, 0 otherwise. +*/ +int SDL_imageFilterMMXdetect(void) +{ + unsigned int mmx_bit; + + /* Check override flag */ + if (SDL_imageFilterUseMMX == 0) { + return (0); + } + + mmx_bit = _cpuFlags(); + mmx_bit &= 0x00800000; + mmx_bit = (mmx_bit && 0x00800000); + + return (mmx_bit); +} + +/*! +\brief Disable MMX check for filter functions and and force to use non-MMX C based code. +*/ +void SDL_imageFilterMMXoff() +{ + SDL_imageFilterUseMMX = 0; +} + +/*! +\brief Enable MMX check for filter functions and use MMX code if available. +*/ +void SDL_imageFilterMMXon() +{ + SDL_imageFilterUseMMX = 1; +} + +/* ------------------------------------------------------------------------------------ */ + +/*! +\brief Internal MMX Filter using Add: D = saturation255(S1 + S2) + +\param Src1 Pointer to the start of the first source byte array (S1). +\param Src2 Pointer to the start of the second source byte array (S2). +\param Dest Pointer to the start of the destination byte array (D). +\param SrcLength The number of bytes in the source arrays. + +\return Returns 0 for success or -1 for error. +*/ +int SDL_imageFilterAddMMX(unsigned char *Src1, unsigned char *Src2, unsigned char *Dest, unsigned int SrcLength) +{ +#ifdef USE_MMX +#if !defined(GCC__) + __asm + { + pusha + mov eax, Src1 /* load Src1 address into eax */ + mov ebx, Src2 /* load Src2 address into ebx */ + mov edi, Dest /* load Dest address into edi */ + mov ecx, SrcLength /* load loop counter (SIZE) into ecx */ + shr ecx, 3 /* counter/8 (MMX loads 8 bytes at a time) */ + align 16 /* 16 byte alignment of the loop entry */ +L1010: + movq mm1, [eax] /* load 8 bytes from Src1 into mm1 */ + paddusb mm1, [ebx] /* mm1=Src1+Src2 (add 8 bytes with saturation) */ + movq [edi], mm1 /* store result in Dest */ + add eax, 8 /* increase Src1, Src2 and Dest */ + add ebx, 8 /* register pointers by 8 */ + add edi, 8 + dec ecx /* decrease loop counter */ + jnz L1010 /* check loop termination, proceed if required */ + emms /* exit MMX state */ + popa + } +#else + asm volatile + ("pusha \n\t" "mov %2, %%eax \n\t" /* load Src1 address into eax */ + "mov %1, %%ebx \n\t" /* load Src2 address into ebx */ + "mov %0, %%edi \n\t" /* load Dest address into edi */ + "mov %3, %%ecx \n\t" /* load loop counter (SIZE) into ecx */ + "shr $3, %%ecx \n\t" /* counter/8 (MMX loads 8 bytes at a time) */ + ".align 16 \n\t" /* 16 byte alignment of the loop entry */ + "1: movq (%%eax), %%mm1 \n\t" /* load 8 bytes from Src1 into mm1 */ + "paddusb (%%ebx), %%mm1 \n\t" /* mm1=Src1+Src2 (add 8 bytes with saturation) */ + "movq %%mm1, (%%edi) \n\t" /* store result in Dest */ + "add $8, %%eax \n\t" /* increase Src1, Src2 and Dest */ + "add $8, %%ebx \n\t" /* register pointers by 8 */ + "add $8, %%edi \n\t" "dec %%ecx \n\t" /* decrease loop counter */ + "jnz 1b \n\t" /* check loop termination, proceed if required */ + "emms \n\t" /* exit MMX state */ + "popa \n\t":"=m" (Dest) /* %0 */ + :"m"(Src2), /* %1 */ + "m"(Src1), /* %2 */ + "m"(SrcLength) /* %3 */ + ); +#endif + return (0); +#else + return (-1); +#endif +} + +/*! +\brief Filter using Add: D = saturation255(S1 + S2) + +\param Src1 Pointer to the start of the first source byte array (S1). +\param Src2 Pointer to the start of the second source byte array (S2). +\param Dest Pointer to the start of the destination byte array (D). +\param length The number of bytes in the source arrays. + +\return Returns 0 for success or -1 for error. +*/ +int SDL_imageFilterAdd(unsigned char *Src1, unsigned char *Src2, unsigned char *Dest, unsigned int length) +{ + unsigned int i, istart; + unsigned char *cursrc1, *cursrc2, *curdst; + int result; + + /* Validate input parameters */ + if ((Src1 == NULL) || (Src2 == NULL) || (Dest == NULL)) + return(-1); + if (length == 0) + return(0); + + if ((SDL_imageFilterMMXdetect()) && (length > 7)) { + + /* Use MMX assembly routine */ + SDL_imageFilterAddMMX(Src1, Src2, Dest, length); + + /* Check for unaligned bytes */ + if ((length & 7) > 0) { + /* Setup to process unaligned bytes */ + istart = length & 0xfffffff8; + cursrc1 = &Src1[istart]; + cursrc2 = &Src2[istart]; + curdst = &Dest[istart]; + } else { + /* No unaligned bytes - we are done */ + return (0); + } + } else { + /* Setup to process whole image */ + istart = 0; + cursrc1 = Src1; + cursrc2 = Src2; + curdst = Dest; + } + + /* C routine to process image */ + for (i = istart; i < length; i++) { + result = (int) *cursrc1 + (int) *cursrc2; + if (result > 255) + result = 255; + *curdst = (unsigned char) result; + /* Advance pointers */ + cursrc1++; + cursrc2++; + curdst++; + } + + return (0); +} + +/*! +\brief Internal MMX Filter using Mean: D = S1/2 + S2/2 + +\param Src1 Pointer to the start of the first source byte array (S1). +\param Src2 Pointer to the start of the second source byte array (S2). +\param Dest Pointer to the start of the destination byte array (D). +\param SrcLength The number of bytes in the source arrays. +\param Mask Mask array containing 8 bytes with 0x7F value. +] +\return Returns 0 for success or -1 for error. +*/ +int SDL_imageFilterMeanMMX(unsigned char *Src1, unsigned char *Src2, unsigned char *Dest, unsigned int SrcLength, + unsigned char *Mask) +{ +#ifdef USE_MMX +#if !defined(GCC__) + __asm + { + pusha + mov edx, Mask /* load Mask address into edx */ + movq mm0, [edx] /* load Mask into mm0 */ + mov eax, Src1 /* load Src1 address into eax */ + mov ebx, Src2 /* load Src2 address into ebx */ + mov edi, Dest /* load Dest address into edi */ + mov ecx, SrcLength /* load loop counter (SIZE) into ecx */ + shr ecx, 3 /* counter/8 (MMX loads 8 bytes at a time) */ + align 16 /* 16 byte alignment of the loop entry */ +L21011: + movq mm1, [eax] /* load 8 bytes from Src1 into mm1 */ + movq mm2, [ebx] /* load 8 bytes from Src2 into mm2 */ + /* --- Byte shift via Word shift --- */ + psrlw mm1, 1 /* shift 4 WORDS of mm1 1 bit to the right */ + psrlw mm2, 1 /* shift 4 WORDS of mm2 1 bit to the right */ + pand mm1, mm0 // apply Mask to 8 BYTES of mm1 */ + /* byte 0x0f, 0xdb, 0xc8 */ + pand mm2, mm0 // apply Mask to 8 BYTES of mm2 */ + /* byte 0x0f, 0xdb, 0xd0 */ + paddusb mm1, mm2 /* mm1=mm1+mm2 (add 8 bytes with saturation) */ + movq [edi], mm1 /* store result in Dest */ + add eax, 8 /* increase Src1, Src2 and Dest */ + add ebx, 8 /* register pointers by 8 */ + add edi, 8 + dec ecx /* decrease loop counter */ + jnz L21011 /* check loop termination, proceed if required */ + emms /* exit MMX state */ + popa + } +#else + asm volatile + ("pusha \n\t" "movl %4, %%edx \n\t" /* load Mask address into edx */ + "movq (%%edx), %%mm0 \n\t" /* load Mask into mm0 */ + "mov %2, %%eax \n\t" /* load Src1 address into eax */ + "mov %1, %%ebx \n\t" /* load Src2 address into ebx */ + "mov %0, %%edi \n\t" /* load Dest address into edi */ + "mov %3, %%ecx \n\t" /* load loop counter (SIZE) into ecx */ + "shr $3, %%ecx \n\t" /* counter/8 (MMX loads 8 bytes at a time) */ + ".align 16 \n\t" /* 16 byte alignment of the loop entry */ + "1: \n\t" + "movq (%%eax), %%mm1 \n\t" /* load 8 bytes from Src1 into mm1 */ + "movq (%%ebx), %%mm2 \n\t" /* load 8 bytes from Src2 into mm2 */ + /* --- Byte shift via Word shift --- */ + "psrlw $1, %%mm1 \n\t" /* shift 4 WORDS of mm1 1 bit to the right */ + "psrlw $1, %%mm2 \n\t" /* shift 4 WORDS of mm2 1 bit to the right */ + /* "pand %%mm0, %%mm1 \n\t" // apply Mask to 8 BYTES of mm1 */ + ".byte 0x0f, 0xdb, 0xc8 \n\t" + /* "pand %%mm0, %%mm2 \n\t" // apply Mask to 8 BYTES of mm2 */ + ".byte 0x0f, 0xdb, 0xd0 \n\t" + "paddusb %%mm2, %%mm1 \n\t" /* mm1=mm1+mm2 (add 8 bytes with saturation) */ + "movq %%mm1, (%%edi) \n\t" /* store result in Dest */ + "add $8, %%eax \n\t" /* increase Src1, Src2 and Dest */ + "add $8, %%ebx \n\t" /* register pointers by 8 */ + "add $8, %%edi \n\t" + "dec %%ecx \n\t" /* decrease loop counter */ + "jnz 1b \n\t" /* check loop termination, proceed if required */ + "emms \n\t" /* exit MMX state */ + "popa \n\t":"=m" (Dest) /* %0 */ + :"m"(Src2), /* %1 */ + "m"(Src1), /* %2 */ + "m"(SrcLength), /* %3 */ + "m"(Mask) /* %4 */ + ); +#endif + return (0); +#else + return (-1); +#endif +} + +/*! +\brief Filter using Mean: D = S1/2 + S2/2 + +\param Src1 Pointer to the start of the first source byte array (S1). +\param Src2 Pointer to the start of the second source byte array (S2). +\param Dest Pointer to the start of the destination byte array (D). +\param length The number of bytes in the source arrays. + +\return Returns 0 for success or -1 for error. +*/ +int SDL_imageFilterMean(unsigned char *Src1, unsigned char *Src2, unsigned char *Dest, unsigned int length) +{ + static unsigned char Mask[8] = { 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F }; + unsigned int i, istart; + unsigned char *cursrc1, *cursrc2, *curdst; + int result; + + /* Validate input parameters */ + if ((Src1 == NULL) || (Src2 == NULL) || (Dest == NULL)) + return(-1); + if (length == 0) + return(0); + + if ((SDL_imageFilterMMXdetect()) && (length > 7)) { + /* MMX routine */ + SDL_imageFilterMeanMMX(Src1, Src2, Dest, length, Mask); + + /* Check for unaligned bytes */ + if ((length & 7) > 0) { + /* Setup to process unaligned bytes */ + istart = length & 0xfffffff8; + cursrc1 = &Src1[istart]; + cursrc2 = &Src2[istart]; + curdst = &Dest[istart]; + } else { + /* No unaligned bytes - we are done */ + return (0); + } + } else { + /* Setup to process whole image */ + istart = 0; + cursrc1 = Src1; + cursrc2 = Src2; + curdst = Dest; + } + + /* C routine to process image */ + for (i = istart; i < length; i++) { + result = (int) *cursrc1 / 2 + (int) *cursrc2 / 2; + *curdst = (unsigned char) result; + /* Advance pointers */ + cursrc1++; + cursrc2++; + curdst++; + } + + return (0); +} + +/*! +\brief Internal MMX Filter using Sub: D = saturation0(S1 - S2) + +\param Src1 Pointer to the start of the first source byte array (S1). +\param Src2 Pointer to the start of the second source byte array (S2). +\param Dest Pointer to the start of the destination byte array (D). +\param SrcLength The number of bytes in the source arrays. + +\return Returns 0 for success or -1 for error. +*/ +int SDL_imageFilterSubMMX(unsigned char *Src1, unsigned char *Src2, unsigned char *Dest, unsigned int SrcLength) +{ +#ifdef USE_MMX +#if !defined(GCC__) + __asm + { + pusha + mov eax, Src1 /* load Src1 address into eax */ + mov ebx, Src2 /* load Src2 address into ebx */ + mov edi, Dest /* load Dest address into edi */ + mov ecx, SrcLength /* load loop counter (SIZE) into ecx */ + shr ecx, 3 /* counter/8 (MMX loads 8 bytes at a time) */ + align 16 /* 16 byte alignment of the loop entry */ +L1012: + movq mm1, [eax] /* load 8 bytes from Src1 into mm1 */ + psubusb mm1, [ebx] /* mm1=Src1-Src2 (sub 8 bytes with saturation) */ + movq [edi], mm1 /* store result in Dest */ + add eax, 8 /* increase Src1, Src2 and Dest */ + add ebx, 8 /* register pointers by 8 */ + add edi, 8 + dec ecx /* decrease loop counter */ + jnz L1012 /* check loop termination, proceed if required */ + emms /* exit MMX state */ + popa + } +#else + asm volatile + ("pusha \n\t" "mov %2, %%eax \n\t" /* load Src1 address into eax */ + "mov %1, %%ebx \n\t" /* load Src2 address into ebx */ + "mov %0, %%edi \n\t" /* load Dest address into edi */ + "mov %3, %%ecx \n\t" /* load loop counter (SIZE) into ecx */ + "shr $3, %%ecx \n\t" /* counter/8 (MMX loads 8 bytes at a time) */ + ".align 16 \n\t" /* 16 byte alignment of the loop entry */ + "1: movq (%%eax), %%mm1 \n\t" /* load 8 bytes from Src1 into mm1 */ + "psubusb (%%ebx), %%mm1 \n\t" /* mm1=Src1-Src2 (sub 8 bytes with saturation) */ + "movq %%mm1, (%%edi) \n\t" /* store result in Dest */ + "add $8, %%eax \n\t" /* increase Src1, Src2 and Dest */ + "add $8, %%ebx \n\t" /* register pointers by 8 */ + "add $8, %%edi \n\t" "dec %%ecx \n\t" /* decrease loop counter */ + "jnz 1b \n\t" /* check loop termination, proceed if required */ + "emms \n\t" /* exit MMX state */ + "popa \n\t":"=m" (Dest) /* %0 */ + :"m"(Src2), /* %1 */ + "m"(Src1), /* %2 */ + "m"(SrcLength) /* %3 */ + ); +#endif + return (0); +#else + return (-1); +#endif +} + +/*! +\brief Filter using Sub: D = saturation0(S1 - S2) + +\param Src1 Pointer to the start of the first source byte array (S1). +\param Src2 Pointer to the start of the second source byte array (S2). +\param Dest Pointer to the start of the destination byte array (D). +\param length The number of bytes in the source arrays. + +\return Returns 0 for success or -1 for error. +*/ +int SDL_imageFilterSub(unsigned char *Src1, unsigned char *Src2, unsigned char *Dest, unsigned int length) +{ + unsigned int i, istart; + unsigned char *cursrc1, *cursrc2, *curdst; + int result; + + /* Validate input parameters */ + if ((Src1 == NULL) || (Src2 == NULL) || (Dest == NULL)) + return(-1); + if (length == 0) + return(0); + + if ((SDL_imageFilterMMXdetect()) && (length > 7)) { + /* MMX routine */ + SDL_imageFilterSubMMX(Src1, Src2, Dest, length); + + /* Check for unaligned bytes */ + if ((length & 7) > 0) { + /* Setup to process unaligned bytes */ + istart = length & 0xfffffff8; + cursrc1 = &Src1[istart]; + cursrc2 = &Src2[istart]; + curdst = &Dest[istart]; + } else { + /* No unaligned bytes - we are done */ + return (0); + } + } else { + /* Setup to process whole image */ + istart = 0; + cursrc1 = Src1; + cursrc2 = Src2; + curdst = Dest; + } + + /* C routine to process image */ + for (i = istart; i < length; i++) { + result = (int) *cursrc1 - (int) *cursrc2; + if (result < 0) + result = 0; + *curdst = (unsigned char) result; + /* Advance pointers */ + cursrc1++; + cursrc2++; + curdst++; + } + + return (0); +} + +/*! +\brief Internal MMX Filter using AbsDiff: D = | S1 - S2 | + +\param Src1 Pointer to the start of the first source byte array (S1). +\param Src2 Pointer to the start of the second source byte array (S2). +\param Dest Pointer to the start of the destination byte array (D). +\param SrcLength The number of bytes in the source arrays. + +\return Returns 0 for success or -1 for error. +*/ +int SDL_imageFilterAbsDiffMMX(unsigned char *Src1, unsigned char *Src2, unsigned char *Dest, unsigned int SrcLength) +{ +#ifdef USE_MMX +#if !defined(GCC__) + __asm + { + pusha + mov eax, Src1 /* load Src1 address into eax */ + mov ebx, Src2 /* load Src2 address into ebx */ + mov edi, Dest /* load Dest address into edi */ + mov ecx, SrcLength /* load loop counter (SIZE) into ecx */ + shr ecx, 3 /* counter/8 (MMX loads 8 bytes at a time) */ + align 16 /* 16 byte alignment of the loop entry */ +L1013: + movq mm1, [eax] /* load 8 bytes from Src1 into mm1 */ + movq mm2, [ebx] /* load 8 bytes from Src2 into mm2 */ + psubusb mm1, [ebx] /* mm1=Src1-Src2 (sub 8 bytes with saturation) */ + psubusb mm2, [eax] /* mm2=Src2-Src1 (sub 8 bytes with saturation) */ + por mm1, mm2 /* combine both mm2 and mm1 results */ + movq [edi], mm1 /* store result in Dest */ + add eax, 8 /* increase Src1, Src2 and Dest */ + add ebx, 8 /* register pointers by 8 */ + add edi, 8 + dec ecx /* decrease loop counter */ + jnz L1013 /* check loop termination, proceed if required */ + emms /* exit MMX state */ + popa + } +#else + asm volatile + ("pusha \n\t" "mov %2, %%eax \n\t" /* load Src1 address into eax */ + "mov %1, %%ebx \n\t" /* load Src2 address into ebx */ + "mov %0, %%edi \n\t" /* load Dest address into edi */ + "mov %3, %%ecx \n\t" /* load loop counter (SIZE) into ecx */ + "shr $3, %%ecx \n\t" /* counter/8 (MMX loads 8 bytes at a time) */ + ".align 16 \n\t" /* 16 byte alignment of the loop entry */ + "1: movq (%%eax), %%mm1 \n\t" /* load 8 bytes from Src1 into mm1 */ + "movq (%%ebx), %%mm2 \n\t" /* load 8 bytes from Src2 into mm2 */ + "psubusb (%%ebx), %%mm1 \n\t" /* mm1=Src1-Src2 (sub 8 bytes with saturation) */ + "psubusb (%%eax), %%mm2 \n\t" /* mm2=Src2-Src1 (sub 8 bytes with saturation) */ + "por %%mm2, %%mm1 \n\t" /* combine both mm2 and mm1 results */ + "movq %%mm1, (%%edi) \n\t" /* store result in Dest */ + "add $8, %%eax \n\t" /* increase Src1, Src2 and Dest */ + "add $8, %%ebx \n\t" /* register pointers by 8 */ + "add $8, %%edi \n\t" "dec %%ecx \n\t" /* decrease loop counter */ + "jnz 1b \n\t" /* check loop termination, proceed if required */ + "emms \n\t" /* exit MMX state */ + "popa \n\t":"=m" (Dest) /* %0 */ + :"m"(Src2), /* %1 */ + "m"(Src1), /* %2 */ + "m"(SrcLength) /* %3 */ + ); +#endif + return (0); +#else + return (-1); +#endif +} + +/*! +\brief Filter using AbsDiff: D = | S1 - S2 | + +\param Src1 Pointer to the start of the first source byte array (S1). +\param Src2 Pointer to the start of the second source byte array (S2). +\param Dest Pointer to the start of the destination byte array (D). +\param length The number of bytes in the source arrays. + +\return Returns 0 for success or -1 for error. +*/ +int SDL_imageFilterAbsDiff(unsigned char *Src1, unsigned char *Src2, unsigned char *Dest, unsigned int length) +{ + unsigned int i, istart; + unsigned char *cursrc1, *cursrc2, *curdst; + int result; + + /* Validate input parameters */ + if ((Src1 == NULL) || (Src2 == NULL) || (Dest == NULL)) + return(-1); + if (length == 0) + return(0); + + if ((SDL_imageFilterMMXdetect()) && (length > 7)) { + /* MMX routine */ + SDL_imageFilterAbsDiffMMX(Src1, Src2, Dest, length); + + /* Check for unaligned bytes */ + if ((length & 7) > 0) { + /* Setup to process unaligned bytes */ + istart = length & 0xfffffff8; + cursrc1 = &Src1[istart]; + cursrc2 = &Src2[istart]; + curdst = &Dest[istart]; + } else { + /* No unaligned bytes - we are done */ + return (0); + } + } else { + /* Setup to process whole image */ + istart = 0; + cursrc1 = Src1; + cursrc2 = Src2; + curdst = Dest; + } + + /* C routine to process image */ + for (i = istart; i < length; i++) { + result = abs((int) *cursrc1 - (int) *cursrc2); + *curdst = (unsigned char) result; + /* Advance pointers */ + cursrc1++; + cursrc2++; + curdst++; + } + + return (0); +} + +/*! +\brief Internal MMX Filter using Mult: D = saturation255(S1 * S2) + +\param Src1 Pointer to the start of the first source byte array (S1). +\param Src2 Pointer to the start of the second source byte array (S2). +\param Dest Pointer to the start of the destination byte array (D). +\param SrcLength The number of bytes in the source arrays. + +\return Returns 0 for success or -1 for error. +*/ +int SDL_imageFilterMultMMX(unsigned char *Src1, unsigned char *Src2, unsigned char *Dest, unsigned int SrcLength) +{ +#ifdef USE_MMX +#if !defined(GCC__) + __asm + { + pusha + mov eax, Src1 /* load Src1 address into eax */ + mov ebx, Src2 /* load Src2 address into ebx */ + mov edi, Dest /* load Dest address into edi */ + mov ecx, SrcLength /* load loop counter (SIZE) into ecx */ + shr ecx, 3 /* counter/8 (MMX loads 8 bytes at a time) */ + pxor mm0, mm0 /* zero mm0 register */ + align 16 /* 16 byte alignment of the loop entry */ +L1014: + movq mm1, [eax] /* load 8 bytes from Src1 into mm1 */ + movq mm3, [ebx] /* load 8 bytes from Src2 into mm3 */ + movq mm2, mm1 /* copy mm1 into mm2 */ + movq mm4, mm3 /* copy mm3 into mm4 */ + punpcklbw mm1, mm0 /* unpack low bytes of Src1 into words */ + punpckhbw mm2, mm0 /* unpack high bytes of Src1 into words */ + punpcklbw mm3, mm0 /* unpack low bytes of Src2 into words */ + punpckhbw mm4, mm0 /* unpack high bytes of Src2 into words */ + pmullw mm1, mm3 /* mul low bytes of Src1 and Src2 */ + pmullw mm2, mm4 /* mul high bytes of Src1 and Src2 */ + /* Take abs value of the results (signed words) */ + movq mm5, mm1 /* copy mm1 into mm5 */ + movq mm6, mm2 /* copy mm2 into mm6 */ + psraw mm5, 15 /* fill mm5 words with word sign bit */ + psraw mm6, 15 /* fill mm6 words with word sign bit */ + pxor mm1, mm5 /* take 1's compliment of only neg. words */ + pxor mm2, mm6 /* take 1's compliment of only neg. words */ + psubsw mm1, mm5 /* add 1 to only neg. words, W-(-1) or W-0 */ + psubsw mm2, mm6 /* add 1 to only neg. words, W-(-1) or W-0 */ + packuswb mm1, mm2 /* pack words back into bytes with saturation */ + movq [edi], mm1 /* store result in Dest */ + add eax, 8 /* increase Src1, Src2 and Dest */ + add ebx, 8 /* register pointers by 8 */ + add edi, 8 + dec ecx /* decrease loop counter */ + jnz L1014 /* check loop termination, proceed if required */ + emms /* exit MMX state */ + popa + } +#else + asm volatile + ("pusha \n\t" "mov %2, %%eax \n\t" /* load Src1 address into eax */ + "mov %1, %%ebx \n\t" /* load Src2 address into ebx */ + "mov %0, %%edi \n\t" /* load Dest address into edi */ + "mov %3, %%ecx \n\t" /* load loop counter (SIZE) into ecx */ + "shr $3, %%ecx \n\t" /* counter/8 (MMX loads 8 bytes at a time) */ + "pxor %%mm0, %%mm0 \n\t" /* zero mm0 register */ + ".align 16 \n\t" /* 16 byte alignment of the loop entry */ + "1: movq (%%eax), %%mm1 \n\t" /* load 8 bytes from Src1 into mm1 */ + "movq (%%ebx), %%mm3 \n\t" /* load 8 bytes from Src2 into mm3 */ + "movq %%mm1, %%mm2 \n\t" /* copy mm1 into mm2 */ + "movq %%mm3, %%mm4 \n\t" /* copy mm3 into mm4 */ + "punpcklbw %%mm0, %%mm1 \n\t" /* unpack low bytes of Src1 into words */ + "punpckhbw %%mm0, %%mm2 \n\t" /* unpack high bytes of Src1 into words */ + "punpcklbw %%mm0, %%mm3 \n\t" /* unpack low bytes of Src2 into words */ + "punpckhbw %%mm0, %%mm4 \n\t" /* unpack high bytes of Src2 into words */ + "pmullw %%mm3, %%mm1 \n\t" /* mul low bytes of Src1 and Src2 */ + "pmullw %%mm4, %%mm2 \n\t" /* mul high bytes of Src1 and Src2 */ + /* Take abs value of the results (signed words) */ + "movq %%mm1, %%mm5 \n\t" /* copy mm1 into mm5 */ + "movq %%mm2, %%mm6 \n\t" /* copy mm2 into mm6 */ + "psraw $15, %%mm5 \n\t" /* fill mm5 words with word sign bit */ + "psraw $15, %%mm6 \n\t" /* fill mm6 words with word sign bit */ + "pxor %%mm5, %%mm1 \n\t" /* take 1's compliment of only neg. words */ + "pxor %%mm6, %%mm2 \n\t" /* take 1's compliment of only neg. words */ + "psubsw %%mm5, %%mm1 \n\t" /* add 1 to only neg. words, W-(-1) or W-0 */ + "psubsw %%mm6, %%mm2 \n\t" /* add 1 to only neg. words, W-(-1) or W-0 */ + "packuswb %%mm2, %%mm1 \n\t" /* pack words back into bytes with saturation */ + "movq %%mm1, (%%edi) \n\t" /* store result in Dest */ + "add $8, %%eax \n\t" /* increase Src1, Src2 and Dest */ + "add $8, %%ebx \n\t" /* register pointers by 8 */ + "add $8, %%edi \n\t" "dec %%ecx \n\t" /* decrease loop counter */ + "jnz 1b \n\t" /* check loop termination, proceed if required */ + "emms \n\t" /* exit MMX state */ + "popa \n\t":"=m" (Dest) /* %0 */ + :"m"(Src2), /* %1 */ + "m"(Src1), /* %2 */ + "m"(SrcLength) /* %3 */ + ); +#endif + return (0); +#else + return (-1); +#endif +} + +/*! +\brief Filter using Mult: D = saturation255(S1 * S2) + +\param Src1 Pointer to the start of the first source byte array (S1). +\param Src2 Pointer to the start of the second source byte array (S2). +\param Dest Pointer to the start of the destination byte array (D). +\param length The number of bytes in the source arrays. + +\return Returns 0 for success or -1 for error. +*/ +int SDL_imageFilterMult(unsigned char *Src1, unsigned char *Src2, unsigned char *Dest, unsigned int length) +{ + unsigned int i, istart; + unsigned char *cursrc1, *cursrc2, *curdst; + int result; + + /* Validate input parameters */ + if ((Src1 == NULL) || (Src2 == NULL) || (Dest == NULL)) + return(-1); + if (length == 0) + return(0); + + if ((SDL_imageFilterMMXdetect()) && (length > 7)) { + /* MMX routine */ + SDL_imageFilterMultMMX(Src1, Src2, Dest, length); + + /* Check for unaligned bytes */ + if ((length & 7) > 0) { + /* Setup to process unaligned bytes */ + istart = length & 0xfffffff8; + cursrc1 = &Src1[istart]; + cursrc2 = &Src2[istart]; + curdst = &Dest[istart]; + } else { + /* No unaligned bytes - we are done */ + return (0); + } + } else { + /* Setup to process whole image */ + istart = 0; + cursrc1 = Src1; + cursrc2 = Src2; + curdst = Dest; + } + + /* C routine to process image */ + for (i = istart; i < length; i++) { + + /* NOTE: this is probably wrong - dunno what the MMX code does */ + + result = (int) *cursrc1 * (int) *cursrc2; + if (result > 255) + result = 255; + *curdst = (unsigned char) result; + /* Advance pointers */ + cursrc1++; + cursrc2++; + curdst++; + } + + return (0); +} + +/*! +\brief Internal ASM Filter using MultNor: D = S1 * S2 + +\param Src1 Pointer to the start of the first source byte array (S1). +\param Src2 Pointer to the start of the second source byte array (S2). +\param Dest Pointer to the start of the destination byte array (D). +\param SrcLength The number of bytes in the source arrays. + +\return Returns 0 for success or -1 for error. +*/ +int SDL_imageFilterMultNorASM(unsigned char *Src1, unsigned char *Src2, unsigned char *Dest, unsigned int SrcLength) +{ +#ifdef USE_MMX +#if !defined(GCC__) + __asm + { + pusha + mov edx, Src1 /* load Src1 address into edx */ + mov esi, Src2 /* load Src2 address into esi */ + mov edi, Dest /* load Dest address into edi */ + mov ecx, SrcLength /* load loop counter (SIZE) into ecx */ + align 16 /* 16 byte alignment of the loop entry */ +L10141: + mov al, [edx] /* load a byte from Src1 */ + mul [esi] /* mul with a byte from Src2 */ + mov [edi], al /* move a byte result to Dest */ + inc edx /* increment Src1, Src2, Dest */ + inc esi /* pointer registers by one */ + inc edi + dec ecx /* decrease loop counter */ + jnz L10141 /* check loop termination, proceed if required */ + popa + } +#else + asm volatile + ("pusha \n\t" "mov %2, %%edx \n\t" /* load Src1 address into edx */ + "mov %1, %%esi \n\t" /* load Src2 address into esi */ + "mov %0, %%edi \n\t" /* load Dest address into edi */ + "mov %3, %%ecx \n\t" /* load loop counter (SIZE) into ecx */ + ".align 16 \n\t" /* 16 byte alignment of the loop entry */ + "1:mov (%%edx), %%al \n\t" /* load a byte from Src1 */ + "mulb (%%esi) \n\t" /* mul with a byte from Src2 */ + "mov %%al, (%%edi) \n\t" /* move a byte result to Dest */ + "inc %%edx \n\t" /* increment Src1, Src2, Dest */ + "inc %%esi \n\t" /* pointer registers by one */ + "inc %%edi \n\t" "dec %%ecx \n\t" /* decrease loop counter */ + "jnz 1b \n\t" /* check loop termination, proceed if required */ + "popa \n\t":"=m" (Dest) /* %0 */ + :"m"(Src2), /* %1 */ + "m"(Src1), /* %2 */ + "m"(SrcLength) /* %3 */ + ); +#endif + return (0); +#else + return (-1); +#endif +} + +/*! +\brief Filter using MultNor: D = S1 * S2 + +\param Src1 Pointer to the start of the first source byte array (S1). +\param Src2 Pointer to the start of the second source byte array (S2). +\param Dest Pointer to the start of the destination byte array (D). +\param length The number of bytes in the source arrays. + +\return Returns 0 for success or -1 for error. +*/ +int SDL_imageFilterMultNor(unsigned char *Src1, unsigned char *Src2, unsigned char *Dest, unsigned int length) +{ + unsigned int i, istart; + unsigned char *cursrc1, *cursrc2, *curdst; + int result; + + /* Validate input parameters */ + if ((Src1 == NULL) || (Src2 == NULL) || (Dest == NULL)) + return(-1); + if (length == 0) + return(0); + + if (SDL_imageFilterMMXdetect()) { + if (length > 0) { + /* ASM routine */ + SDL_imageFilterMultNorASM(Src1, Src2, Dest, length); + + /* Check for unaligned bytes */ + if ((length & 7) > 0) { + /* Setup to process unaligned bytes */ + istart = length & 0xfffffff8; + cursrc1 = &Src1[istart]; + cursrc2 = &Src2[istart]; + curdst = &Dest[istart]; + } else { + /* No unaligned bytes - we are done */ + return (0); + } + } else { + /* No bytes - we are done */ + return (0); + } + } else { + /* Setup to process whole image */ + istart = 0; + cursrc1 = Src1; + cursrc2 = Src2; + curdst = Dest; + } + + /* C routine to process image */ + for (i = istart; i < length; i++) { + result = (int) *cursrc1 * (int) *cursrc2; + *curdst = (unsigned char) result; + /* Advance pointers */ + cursrc1++; + cursrc2++; + curdst++; + } + + return (0); +} + +/*! +\brief Internal MMX Filter using MultDivby2: D = saturation255(S1/2 * S2) + +\param Src1 Pointer to the start of the first source byte array (S1). +\param Src2 Pointer to the start of the second source byte array (S2). +\param Dest Pointer to the start of the destination byte array (D). +\param SrcLength The number of bytes in the source arrays. + +\return Returns 0 for success or -1 for error. +*/ +int SDL_imageFilterMultDivby2MMX(unsigned char *Src1, unsigned char *Src2, unsigned char *Dest, unsigned int SrcLength) +{ +#ifdef USE_MMX +#if !defined(GCC__) + __asm + { + pusha + mov eax, Src1 /* load Src1 address into eax */ + mov ebx, Src2 /* load Src2 address into ebx */ + mov edi, Dest /* load Dest address into edi */ + mov ecx, SrcLength /* load loop counter (SIZE) into ecx */ + shr ecx, 3 /* counter/8 (MMX loads 8 bytes at a time) */ + pxor mm0, mm0 /* zero mm0 register */ + align 16 /* 16 byte alignment of the loop entry */ +L1015: + movq mm1, [eax] /* load 8 bytes from Src1 into mm1 */ + movq mm3, [ebx] /* load 8 bytes from Src2 into mm3 */ + movq mm2, mm1 /* copy mm1 into mm2 */ + movq mm4, mm3 /* copy mm3 into mm4 */ + punpcklbw mm1, mm0 /* unpack low bytes of Src1 into words */ + punpckhbw mm2, mm0 /* unpack high bytes of Src1 into words */ + punpcklbw mm3, mm0 /* unpack low bytes of Src2 into words */ + punpckhbw mm4, mm0 /* unpack high bytes of Src2 into words */ + psrlw mm1, 1 /* divide mm1 words by 2, Src1 low bytes */ + psrlw mm2, 1 /* divide mm2 words by 2, Src1 high bytes */ + pmullw mm1, mm3 /* mul low bytes of Src1 and Src2 */ + pmullw mm2, mm4 /* mul high bytes of Src1 and Src2 */ + packuswb mm1, mm2 /* pack words back into bytes with saturation */ + movq [edi], mm1 /* store result in Dest */ + add eax, 8 /* increase Src1, Src2 and Dest */ + add ebx, 8 /* register pointers by 8 */ + add edi, 8 + dec ecx /* decrease loop counter */ + jnz L1015 /* check loop termination, proceed if required */ + emms /* exit MMX state */ + popa + } +#else + asm volatile + ("pusha \n\t" "mov %2, %%eax \n\t" /* load Src1 address into eax */ + "mov %1, %%ebx \n\t" /* load Src2 address into ebx */ + "mov %0, %%edi \n\t" /* load Dest address into edi */ + "mov %3, %%ecx \n\t" /* load loop counter (SIZE) into ecx */ + "shr $3, %%ecx \n\t" /* counter/8 (MMX loads 8 bytes at a time) */ + "pxor %%mm0, %%mm0 \n\t" /* zero mm0 register */ + ".align 16 \n\t" /* 16 byte alignment of the loop entry */ + "1: movq (%%eax), %%mm1 \n\t" /* load 8 bytes from Src1 into mm1 */ + "movq (%%ebx), %%mm3 \n\t" /* load 8 bytes from Src2 into mm3 */ + "movq %%mm1, %%mm2 \n\t" /* copy mm1 into mm2 */ + "movq %%mm3, %%mm4 \n\t" /* copy mm3 into mm4 */ + "punpcklbw %%mm0, %%mm1 \n\t" /* unpack low bytes of Src1 into words */ + "punpckhbw %%mm0, %%mm2 \n\t" /* unpack high bytes of Src1 into words */ + "punpcklbw %%mm0, %%mm3 \n\t" /* unpack low bytes of Src2 into words */ + "punpckhbw %%mm0, %%mm4 \n\t" /* unpack high bytes of Src2 into words */ + "psrlw $1, %%mm1 \n\t" /* divide mm1 words by 2, Src1 low bytes */ + "psrlw $1, %%mm2 \n\t" /* divide mm2 words by 2, Src1 high bytes */ + "pmullw %%mm3, %%mm1 \n\t" /* mul low bytes of Src1 and Src2 */ + "pmullw %%mm4, %%mm2 \n\t" /* mul high bytes of Src1 and Src2 */ + "packuswb %%mm2, %%mm1 \n\t" /* pack words back into bytes with saturation */ + "movq %%mm1, (%%edi) \n\t" /* store result in Dest */ + "add $8, %%eax \n\t" /* increase Src1, Src2 and Dest */ + "add $8, %%ebx \n\t" /* register pointers by 8 */ + "add $8, %%edi \n\t" "dec %%ecx \n\t" /* decrease loop counter */ + "jnz 1b \n\t" /* check loop termination, proceed if required */ + "emms \n\t" /* exit MMX state */ + "popa \n\t":"=m" (Dest) /* %0 */ + :"m"(Src2), /* %1 */ + "m"(Src1), /* %2 */ + "m"(SrcLength) /* %3 */ + ); +#endif + return (0); +#else + return (-1); +#endif +} + +/*! +\brief Filter using MultDivby2: D = saturation255(S1/2 * S2) + +\param Src1 Pointer to the start of the first source byte array (S1). +\param Src2 Pointer to the start of the second source byte array (S2). +\param Dest Pointer to the start of the destination byte array (D). +\param length The number of bytes in the source arrays. + +\return Returns 0 for success or -1 for error. +*/ +int SDL_imageFilterMultDivby2(unsigned char *Src1, unsigned char *Src2, unsigned char *Dest, unsigned int length) +{ + unsigned int i, istart; + unsigned char *cursrc1, *cursrc2, *curdst; + int result; + + /* Validate input parameters */ + if ((Src1 == NULL) || (Src2 == NULL) || (Dest == NULL)) + return(-1); + if (length == 0) + return(0); + + if ((SDL_imageFilterMMXdetect()) && (length > 7)) { + /* MMX routine */ + SDL_imageFilterMultDivby2MMX(Src1, Src2, Dest, length); + + /* Check for unaligned bytes */ + if ((length & 7) > 0) { + /* Setup to process unaligned bytes */ + istart = length & 0xfffffff8; + cursrc1 = &Src1[istart]; + cursrc2 = &Src2[istart]; + curdst = &Dest[istart]; + } else { + /* No unaligned bytes - we are done */ + return (0); + } + } else { + /* Setup to process whole image */ + istart = 0; + cursrc1 = Src1; + cursrc2 = Src2; + curdst = Dest; + } + + /* C routine to process image */ + for (i = istart; i < length; i++) { + result = ((int) *cursrc1 / 2) * (int) *cursrc2; + if (result > 255) + result = 255; + *curdst = (unsigned char) result; + /* Advance pointers */ + cursrc1++; + cursrc2++; + curdst++; + } + + return (0); +} + +/*! +\brief Internal MMX Filter using MultDivby4: D = saturation255(S1/2 * S2/2) + +\param Src1 Pointer to the start of the first source byte array (S1). +\param Src2 Pointer to the start of the second source byte array (S2). +\param Dest Pointer to the start of the destination byte array (D). +\param SrcLength The number of bytes in the source arrays. + +\return Returns 0 for success or -1 for error. +*/ +int SDL_imageFilterMultDivby4MMX(unsigned char *Src1, unsigned char *Src2, unsigned char *Dest, unsigned int SrcLength) +{ +#ifdef USE_MMX +#if !defined(GCC__) + __asm + { + pusha + mov eax, Src1 /* load Src1 address into eax */ + mov ebx, Src2 /* load Src2 address into ebx */ + mov edi, Dest /* load Dest address into edi */ + mov ecx, SrcLength /* load loop counter (SIZE) into ecx */ + shr ecx, 3 /* counter/8 (MMX loads 8 bytes at a time) */ + pxor mm0, mm0 /* zero mm0 register */ + align 16 /* 16 byte alignment of the loop entry */ +L1016: + movq mm1, [eax] /* load 8 bytes from Src1 into mm1 */ + movq mm3, [ebx] /* load 8 bytes from Src2 into mm3 */ + movq mm2, mm1 /* copy mm1 into mm2 */ + movq mm4, mm3 /* copy mm3 into mm4 */ + punpcklbw mm1, mm0 /* unpack low bytes of Src1 into words */ + punpckhbw mm2, mm0 /* unpack high bytes of Src1 into words */ + punpcklbw mm3, mm0 /* unpack low bytes of Src2 into words */ + punpckhbw mm4, mm0 /* unpack high bytes of Src2 into words */ + psrlw mm1, 1 /* divide mm1 words by 2, Src1 low bytes */ + psrlw mm2, 1 /* divide mm2 words by 2, Src1 high bytes */ + psrlw mm3, 1 /* divide mm3 words by 2, Src2 low bytes */ + psrlw mm4, 1 /* divide mm4 words by 2, Src2 high bytes */ + pmullw mm1, mm3 /* mul low bytes of Src1 and Src2 */ + pmullw mm2, mm4 /* mul high bytes of Src1 and Src2 */ + packuswb mm1, mm2 /* pack words back into bytes with saturation */ + movq [edi], mm1 /* store result in Dest */ + add eax, 8 /* increase Src1, Src2 and Dest */ + add ebx, 8 /* register pointers by 8 */ + add edi, 8 + dec ecx /* decrease loop counter */ + jnz L1016 /* check loop termination, proceed if required */ + emms /* exit MMX state */ + popa + } +#else + asm volatile + ("pusha \n\t" "mov %2, %%eax \n\t" /* load Src1 address into eax */ + "mov %1, %%ebx \n\t" /* load Src2 address into ebx */ + "mov %0, %%edi \n\t" /* load Dest address into edi */ + "mov %3, %%ecx \n\t" /* load loop counter (SIZE) into ecx */ + "shr $3, %%ecx \n\t" /* counter/8 (MMX loads 8 bytes at a time) */ + "pxor %%mm0, %%mm0 \n\t" /* zero mm0 register */ + ".align 16 \n\t" /* 16 byte alignment of the loop entry */ + "1: movq (%%eax), %%mm1 \n\t" /* load 8 bytes from Src1 into mm1 */ + "movq (%%ebx), %%mm3 \n\t" /* load 8 bytes from Src2 into mm3 */ + "movq %%mm1, %%mm2 \n\t" /* copy mm1 into mm2 */ + "movq %%mm3, %%mm4 \n\t" /* copy mm3 into mm4 */ + "punpcklbw %%mm0, %%mm1 \n\t" /* unpack low bytes of Src1 into words */ + "punpckhbw %%mm0, %%mm2 \n\t" /* unpack high bytes of Src1 into words */ + "punpcklbw %%mm0, %%mm3 \n\t" /* unpack low bytes of Src2 into words */ + "punpckhbw %%mm0, %%mm4 \n\t" /* unpack high bytes of Src2 into words */ + "psrlw $1, %%mm1 \n\t" /* divide mm1 words by 2, Src1 low bytes */ + "psrlw $1, %%mm2 \n\t" /* divide mm2 words by 2, Src1 high bytes */ + "psrlw $1, %%mm3 \n\t" /* divide mm3 words by 2, Src2 low bytes */ + "psrlw $1, %%mm4 \n\t" /* divide mm4 words by 2, Src2 high bytes */ + "pmullw %%mm3, %%mm1 \n\t" /* mul low bytes of Src1 and Src2 */ + "pmullw %%mm4, %%mm2 \n\t" /* mul high bytes of Src1 and Src2 */ + "packuswb %%mm2, %%mm1 \n\t" /* pack words back into bytes with saturation */ + "movq %%mm1, (%%edi) \n\t" /* store result in Dest */ + "add $8, %%eax \n\t" /* increase Src1, Src2 and Dest */ + "add $8, %%ebx \n\t" /* register pointers by 8 */ + "add $8, %%edi \n\t" "dec %%ecx \n\t" /* decrease loop counter */ + "jnz 1b \n\t" /* check loop termination, proceed if required */ + "emms \n\t" /* exit MMX state */ + "popa \n\t":"=m" (Dest) /* %0 */ + :"m"(Src2), /* %1 */ + "m"(Src1), /* %2 */ + "m"(SrcLength) /* %3 */ + ); +#endif + return (0); +#else + return (-1); +#endif +} + +/*! +\brief Filter using MultDivby4: D = saturation255(S1/2 * S2/2) + +\param Src1 Pointer to the start of the first source byte array (S1). +\param Src2 Pointer to the start of the second source byte array (S2). +\param Dest Pointer to the start of the destination byte array (D). +\param length The number of bytes in the source arrays. + +\return Returns 0 for success or -1 for error. +*/ +int SDL_imageFilterMultDivby4(unsigned char *Src1, unsigned char *Src2, unsigned char *Dest, unsigned int length) +{ + unsigned int i, istart; + unsigned char *cursrc1, *cursrc2, *curdst; + int result; + + /* Validate input parameters */ + if ((Src1 == NULL) || (Src2 == NULL) || (Dest == NULL)) + return(-1); + if (length == 0) + return(0); + + if ((SDL_imageFilterMMXdetect()) && (length > 7)) { + /* MMX routine */ + SDL_imageFilterMultDivby4MMX(Src1, Src2, Dest, length); + + /* Check for unaligned bytes */ + if ((length & 7) > 0) { + /* Setup to process unaligned bytes */ + istart = length & 0xfffffff8; + cursrc1 = &Src1[istart]; + cursrc2 = &Src2[istart]; + curdst = &Dest[istart]; + } else { + /* No unaligned bytes - we are done */ + return (0); + } + } else { + /* Setup to process whole image */ + istart = 0; + cursrc1 = Src1; + cursrc2 = Src2; + curdst = Dest; + } + + /* C routine to process image */ + for (i = istart; i < length; i++) { + result = ((int) *cursrc1 / 2) * ((int) *cursrc2 / 2); + if (result > 255) + result = 255; + *curdst = (unsigned char) result; + /* Advance pointers */ + cursrc1++; + cursrc2++; + curdst++; + } + + return (0); +} + +/*! +\brief Internal MMX Filter using BitAnd: D = S1 & S2 + +\param Src1 Pointer to the start of the first source byte array (S1). +\param Src2 Pointer to the start of the second source byte array (S2). +\param Dest Pointer to the start of the destination byte array (D). +\param SrcLength The number of bytes in the source arrays. + +\return Returns 0 for success or -1 for error. +*/ +int SDL_imageFilterBitAndMMX(unsigned char *Src1, unsigned char *Src2, unsigned char *Dest, unsigned int SrcLength) +{ +#ifdef USE_MMX +#if !defined(GCC__) + __asm + { + pusha + mov eax, Src1 /* load Src1 address into eax */ + mov ebx, Src2 /* load Src2 address into ebx */ + mov edi, Dest /* load Dest address into edi */ + mov ecx, SrcLength /* load loop counter (SIZE) into ecx */ + shr ecx, 3 /* counter/8 (MMX loads 8 bytes at a time) */ + align 16 /* 16 byte alignment of the loop entry */ +L1017: + movq mm1, [eax] /* load 8 bytes from Src1 into mm1 */ + pand mm1, [ebx] /* mm1=Src1&Src2 */ + movq [edi], mm1 /* store result in Dest */ + add eax, 8 /* increase Src1, Src2 and Dest */ + add ebx, 8 /* register pointers by 8 */ + add edi, 8 + dec ecx /* decrease loop counter */ + jnz L1017 /* check loop termination, proceed if required */ + emms /* exit MMX state */ + popa + } +#else + asm volatile + ("pusha \n\t" "mov %2, %%eax \n\t" /* load Src1 address into eax */ + "mov %1, %%ebx \n\t" /* load Src2 address into ebx */ + "mov %0, %%edi \n\t" /* load Dest address into edi */ + "mov %3, %%ecx \n\t" /* load loop counter (SIZE) into ecx */ + "shr $3, %%ecx \n\t" /* counter/8 (MMX loads 8 bytes at a time) */ + ".align 16 \n\t" /* 16 byte alignment of the loop entry */ + "1: movq (%%eax), %%mm1 \n\t" /* load 8 bytes from Src1 into mm1 */ + "pand (%%ebx), %%mm1 \n\t" /* mm1=Src1&Src2 */ + "movq %%mm1, (%%edi) \n\t" /* store result in Dest */ + "add $8, %%eax \n\t" /* increase Src1, Src2 and Dest */ + "add $8, %%ebx \n\t" /* register pointers by 8 */ + "add $8, %%edi \n\t" "dec %%ecx \n\t" /* decrease loop counter */ + "jnz 1b \n\t" /* check loop termination, proceed if required */ + "emms \n\t" /* exit MMX state */ + "popa \n\t":"=m" (Dest) /* %0 */ + :"m"(Src2), /* %1 */ + "m"(Src1), /* %2 */ + "m"(SrcLength) /* %3 */ + ); +#endif + return (0); +#else + return (-1); +#endif +} + +/*! +\brief Filter using BitAnd: D = S1 & S2 + +\param Src1 Pointer to the start of the first source byte array (S1). +\param Src2 Pointer to the start of the second source byte array (S2). +\param Dest Pointer to the start of the destination byte array (D). +\param length The number of bytes in the source arrays. + +\return Returns 0 for success or -1 for error. +*/ +int SDL_imageFilterBitAnd(unsigned char *Src1, unsigned char *Src2, unsigned char *Dest, unsigned int length) +{ + unsigned int i, istart; + unsigned char *cursrc1, *cursrc2, *curdst; + + /* Validate input parameters */ + if ((Src1 == NULL) || (Src2 == NULL) || (Dest == NULL)) + return(-1); + if (length == 0) + return(0); + + if ((SDL_imageFilterMMXdetect()>0) && (length>7)) { + /* if (length > 7) { */ + /* Call MMX routine */ + + SDL_imageFilterBitAndMMX(Src1, Src2, Dest, length); + + /* Check for unaligned bytes */ + if ((length & 7) > 0) { + + /* Setup to process unaligned bytes */ + istart = length & 0xfffffff8; + cursrc1 = &Src1[istart]; + cursrc2 = &Src2[istart]; + curdst = &Dest[istart]; + } else { + /* No unaligned bytes - we are done */ + return (0); + } + } else { + /* Setup to process whole image */ + istart = 0; + cursrc1 = Src1; + cursrc2 = Src2; + curdst = Dest; + } + + /* C routine to process image */ + for (i = istart; i < length; i++) { + *curdst = (*cursrc1) & (*cursrc2); + /* Advance pointers */ + cursrc1++; + cursrc2++; + curdst++; + } + + return (0); +} + +/*! +\brief Internal MMX Filter using BitOr: D = S1 | S2 + +\param Src1 Pointer to the start of the first source byte array (S1). +\param Src2 Pointer to the start of the second source byte array (S2). +\param Dest Pointer to the start of the destination byte array (D). +\param SrcLength The number of bytes in the source arrays. + +\return Returns 0 for success or -1 for error. +*/ +int SDL_imageFilterBitOrMMX(unsigned char *Src1, unsigned char *Src2, unsigned char *Dest, unsigned int SrcLength) +{ +#ifdef USE_MMX +#if !defined(GCC__) + __asm + { + pusha + mov eax, Src1 /* load Src1 address into eax */ + mov ebx, Src2 /* load Src2 address into ebx */ + mov edi, Dest /* load Dest address into edi */ + mov ecx, SrcLength /* load loop counter (SIZE) into ecx */ + shr ecx, 3 /* counter/8 (MMX loads 8 bytes at a time) */ + align 16 /* 16 byte alignment of the loop entry */ +L91017: + movq mm1, [eax] /* load 8 bytes from Src1 into mm1 */ + por mm1, [ebx] /* mm1=Src1|Src2 */ + movq [edi], mm1 /* store result in Dest */ + add eax, 8 /* increase Src1, Src2 and Dest */ + add ebx, 8 /* register pointers by 8 */ + add edi, 8 + dec ecx /* decrease loop counter */ + jnz L91017 /* check loop termination, proceed if required */ + emms /* exit MMX state */ + popa + } +#else + asm volatile + ("pusha \n\t" "mov %2, %%eax \n\t" /* load Src1 address into eax */ + "mov %1, %%ebx \n\t" /* load Src2 address into ebx */ + "mov %0, %%edi \n\t" /* load Dest address into edi */ + "mov %3, %%ecx \n\t" /* load loop counter (SIZE) into ecx */ + "shr $3, %%ecx \n\t" /* counter/8 (MMX loads 8 bytes at a time) */ + ".align 16 \n\t" /* 16 byte alignment of the loop entry */ + "1: movq (%%eax), %%mm1 \n\t" /* load 8 bytes from Src1 into mm1 */ + "por (%%ebx), %%mm1 \n\t" /* mm1=Src1|Src2 */ + "movq %%mm1, (%%edi) \n\t" /* store result in Dest */ + "add $8, %%eax \n\t" /* increase Src1, Src2 and Dest */ + "add $8, %%ebx \n\t" /* register pointers by 8 */ + "add $8, %%edi \n\t" "dec %%ecx \n\t" /* decrease loop counter */ + "jnz 1b \n\t" /* check loop termination, proceed if required */ + "emms \n\t" /* exit MMX state */ + "popa \n\t":"=m" (Dest) /* %0 */ + :"m"(Src2), /* %1 */ + "m"(Src1), /* %2 */ + "m"(SrcLength) /* %3 */ + ); +#endif + return (0); +#else + return (-1); +#endif +} + +/*! +\brief Filter using BitOr: D = S1 | S2 + +\param Src1 Pointer to the start of the first source byte array (S1). +\param Src2 Pointer to the start of the second source byte array (S2). +\param Dest Pointer to the start of the destination byte array (D). +\param length The number of bytes in the source arrays. + +\return Returns 0 for success or -1 for error. +*/ +int SDL_imageFilterBitOr(unsigned char *Src1, unsigned char *Src2, unsigned char *Dest, unsigned int length) +{ + unsigned int i, istart; + unsigned char *cursrc1, *cursrc2, *curdst; + + /* Validate input parameters */ + if ((Src1 == NULL) || (Src2 == NULL) || (Dest == NULL)) + return(-1); + if (length == 0) + return(0); + + if ((SDL_imageFilterMMXdetect()) && (length > 7)) { + + /* MMX routine */ + SDL_imageFilterBitOrMMX(Src1, Src2, Dest, length); + + /* Check for unaligned bytes */ + if ((length & 7) > 0) { + /* Setup to process unaligned bytes */ + istart = length & 0xfffffff8; + cursrc1 = &Src1[istart]; + cursrc2 = &Src2[istart]; + curdst = &Dest[istart]; + } else { + /* No unaligned bytes - we are done */ + return (0); + } + } else { + /* Setup to process whole image */ + istart = 0; + cursrc1 = Src1; + cursrc2 = Src2; + curdst = Dest; + } + + /* C routine to process image */ + for (i = istart; i < length; i++) { + *curdst = *cursrc1 | *cursrc2; + /* Advance pointers */ + cursrc1++; + cursrc2++; + curdst++; + } + return (0); +} + +/*! +\brief Internal ASM Filter using Div: D = S1 / S2 + +\param Src1 Pointer to the start of the first source byte array (S1). +\param Src2 Pointer to the start of the second source byte array (S2). +\param Dest Pointer to the start of the destination byte array (D). +\param SrcLength The number of bytes in the source arrays. + +\return Returns 0 for success or -1 for error. +*/ +int SDL_imageFilterDivASM(unsigned char *Src1, unsigned char *Src2, unsigned char *Dest, unsigned int SrcLength) +{ +#ifdef USE_MMX +#if !defined(GCC__) + __asm + { + pusha + mov edx, Src1 /* load Src1 address into edx */ + mov esi, Src2 /* load Src2 address into esi */ + mov edi, Dest /* load Dest address into edi */ + mov ecx, SrcLength /* load loop counter (SIZE) into ecx */ + align 16 /* 16 byte alignment of the loop entry */ +L10191: + mov bl, [esi] /* load a byte from Src2 */ + cmp bl, 0 /* check if it zero */ + jnz L10192 + mov [edi], 255 /* division by zero = 255 !!! */ + jmp L10193 +L10192: + xor ah, ah /* prepare AX, zero AH register */ + mov al, [edx] /* load a byte from Src1 into AL */ + div bl /* divide AL by BL */ + mov [edi], al /* move a byte result to Dest */ +L10193: + inc edx /* increment Src1, Src2, Dest */ + inc esi /* pointer registers by one */ + inc edi + dec ecx /* decrease loop counter */ + jnz L10191 /* check loop termination, proceed if required */ + popa + } +#else + asm volatile + ("pusha \n\t" "mov %2, %%edx \n\t" /* load Src1 address into edx */ + "mov %1, %%esi \n\t" /* load Src2 address into esi */ + "mov %0, %%edi \n\t" /* load Dest address into edi */ + "mov %3, %%ecx \n\t" /* load loop counter (SIZE) into ecx */ + ".align 16 \n\t" /* 16 byte alignment of the loop entry */ + "1: mov (%%esi), %%bl \n\t" /* load a byte from Src2 */ + "cmp $0, %%bl \n\t" /* check if it zero */ + "jnz 2f \n\t" "movb $255, (%%edi) \n\t" /* division by zero = 255 !!! */ + "jmp 3f \n\t" "2: \n\t" "xor %%ah, %%ah \n\t" /* prepare AX, zero AH register */ + "mov (%%edx), %%al \n\t" /* load a byte from Src1 into AL */ + "div %%bl \n\t" /* divide AL by BL */ + "mov %%al, (%%edi) \n\t" /* move a byte result to Dest */ + "3: inc %%edx \n\t" /* increment Src1, Src2, Dest */ + "inc %%esi \n\t" /* pointer registers by one */ + "inc %%edi \n\t" "dec %%ecx \n\t" /* decrease loop counter */ + "jnz 1b \n\t" /* check loop termination, proceed if required */ + "popa \n\t":"=m" (Dest) /* %0 */ + :"m"(Src2), /* %1 */ + "m"(Src1), /* %2 */ + "m"(SrcLength) /* %3 */ + ); +#endif + return (0); +#else + return (-1); +#endif +} + +/*! +\brief Filter using Div: D = S1 / S2 + +\param Src1 Pointer to the start of the first source byte array (S1). +\param Src2 Pointer to the start of the second source byte array (S2). +\param Dest Pointer to the start of the destination byte array (D). +\param length The number of bytes in the source arrays. + +\return Returns 0 for success or -1 for error. +*/ +int SDL_imageFilterDiv(unsigned char *Src1, unsigned char *Src2, unsigned char *Dest, unsigned int length) +{ + unsigned int i, istart; + unsigned char *cursrc1, *cursrc2, *curdst; + int result; + + /* Validate input parameters */ + if ((Src1 == NULL) || (Src2 == NULL) || (Dest == NULL)) + return(-1); + if (length == 0) + return(0); + + if (SDL_imageFilterMMXdetect()) { + if (length > 0) { + /* Call ASM routine */ + SDL_imageFilterDivASM(Src1, Src2, Dest, length); + + /* Never unaligned bytes - we are done */ + return (0); + } else { + return (-1); + } + } else { + /* Setup to process whole image */ + istart = 0; + cursrc1 = Src1; + cursrc2 = Src2; + curdst = Dest; + } + + /* C routine to process image */ + for (i = istart; i < length; i++) { + result = (int) *cursrc1 / (int) *cursrc2; + *curdst = (unsigned char) result; + /* Advance pointers */ + cursrc1++; + cursrc2++; + curdst++; + } + + return (0); +} + +/* ------------------------------------------------------------------------------------ */ + +/*! +\brief Internal MMX Filter using BitNegation: D = !S + +\param Src1 Pointer to the start of the source byte array (S1). +\param Dest Pointer to the start of the destination byte array (D). +\param SrcLength The number of bytes in the source array. + +\return Returns 0 for success or -1 for error. +*/ +int SDL_imageFilterBitNegationMMX(unsigned char *Src1, unsigned char *Dest, unsigned int SrcLength) +{ +#ifdef USE_MMX +#if !defined(GCC__) + __asm + { + pusha + pcmpeqb mm1, mm1 /* generate all 1's in mm1 */ + mov eax, Src1 /* load Src1 address into eax */ + mov edi, Dest /* load Dest address into edi */ + mov ecx, SrcLength /* load loop counter (SIZE) into ecx */ + shr ecx, 3 /* counter/8 (MMX loads 8 bytes at a time) */ + align 16 /* 16 byte alignment of the loop entry */ +L91117: + movq mm0, [eax] /* load 8 bytes from Src1 into mm1 */ + pxor mm0, mm1 /* negate mm0 by xoring with mm1 */ + movq [edi], mm0 /* store result in Dest */ + add eax, 8 /* increase Src1, Src2 and Dest */ + add edi, 8 + dec ecx /* decrease loop counter */ + jnz L91117 /* check loop termination, proceed if required */ + emms /* exit MMX state */ + popa + } +#else + asm volatile + ("pusha \n\t" "pcmpeqb %%mm1, %%mm1 \n\t" /* generate all 1's in mm1 */ + "mov %1, %%eax \n\t" /* load Src1 address into eax */ + "mov %0, %%edi \n\t" /* load Dest address into edi */ + "mov %2, %%ecx \n\t" /* load loop counter (SIZE) into ecx */ + "shr $3, %%ecx \n\t" /* counter/8 (MMX loads 8 bytes at a time) */ + ".align 16 \n\t" /* 16 byte alignment of the loop entry */ + "1: movq (%%eax), %%mm0 \n\t" /* load 8 bytes from Src1 into mm1 */ + "pxor %%mm1, %%mm0 \n\t" /* negate mm0 by xoring with mm1 */ + "movq %%mm0, (%%edi) \n\t" /* store result in Dest */ + "add $8, %%eax \n\t" /* increase Src1, Src2 and Dest */ + "add $8, %%edi \n\t" "dec %%ecx \n\t" /* decrease loop counter */ + "jnz 1b \n\t" /* check loop termination, proceed if required */ + "emms \n\t" /* exit MMX state */ + "popa \n\t":"=m" (Dest) /* %0 */ + :"m"(Src1), /* %1 */ + "m"(SrcLength) /* %2 */ + ); +#endif + return (0); +#else + return (-1); +#endif +} + +/*! +\brief Filter using BitNegation: D = !S + +\param Src1 Pointer to the start of the source byte array (S). +\param Dest Pointer to the start of the destination byte array (D). +\param length The number of bytes in the source array. + +\return Returns 0 for success or -1 for error. +*/ +int SDL_imageFilterBitNegation(unsigned char *Src1, unsigned char *Dest, unsigned int length) +{ + unsigned int i, istart; + unsigned char *cursrc1, *curdst; + + /* Validate input parameters */ + if ((Src1 == NULL) || (Dest == NULL)) + return(-1); + if (length == 0) + return(0); + + if ((SDL_imageFilterMMXdetect()) && (length > 7)) { + /* MMX routine */ + SDL_imageFilterBitNegationMMX(Src1, Dest, length); + + /* Check for unaligned bytes */ + if ((length & 7) > 0) { + /* Setup to process unaligned bytes */ + istart = length & 0xfffffff8; + cursrc1 = &Src1[istart]; + curdst = &Dest[istart]; + } else { + /* No unaligned bytes - we are done */ + return (0); + } + } else { + /* Setup to process whole image */ + istart = 0; + cursrc1 = Src1; + curdst = Dest; + } + + /* C routine to process image */ + for (i = istart; i < length; i++) { + *curdst = ~(*cursrc1); + /* Advance pointers */ + cursrc1++; + curdst++; + } + + return (0); +} + +/*! +\brief Internal MMX Filter using AddByte: D = saturation255(S + C) + +\param Src1 Pointer to the start of the source byte array (S). +\param Dest Pointer to the start of the destination byte array (D). +\param SrcLength The number of bytes in the source array. +\param C Constant value to add (C). + +\return Returns 0 for success or -1 for error. +*/ +int SDL_imageFilterAddByteMMX(unsigned char *Src1, unsigned char *Dest, unsigned int SrcLength, unsigned char C) +{ +#ifdef USE_MMX +#if !defined(GCC__) + __asm + { + pusha + /* ** Duplicate C in 8 bytes of MM1 ** */ + mov al, C /* load C into AL */ + mov ah, al /* copy AL into AH */ + mov bx, ax /* copy AX into BX */ + shl eax, 16 /* shift 2 bytes of EAX left */ + mov ax, bx /* copy BX into AX */ + movd mm1, eax /* copy EAX into MM1 */ + movd mm2, eax /* copy EAX into MM2 */ + punpckldq mm1, mm2 /* fill higher bytes of MM1 with C */ + mov eax, Src1 /* load Src1 address into eax */ + mov edi, Dest /* load Dest address into edi */ + mov ecx, SrcLength /* load loop counter (SIZE) into ecx */ + shr ecx, 3 /* counter/8 (MMX loads 8 bytes at a time) */ + align 16 /* 16 byte alignment of the loop entry */ +L1021: + movq mm0, [eax] /* load 8 bytes from Src1 into MM0 */ + paddusb mm0, mm1 /* MM0=SrcDest+C (add 8 bytes with saturation) */ + movq [edi], mm0 /* store result in Dest */ + add eax, 8 /* increase Dest register pointer by 8 */ + add edi, 8 /* increase Dest register pointer by 8 */ + dec ecx /* decrease loop counter */ + jnz L1021 /* check loop termination, proceed if required */ + emms /* exit MMX state */ + popa + } +#else + asm volatile + ("pusha \n\t" + /* ** Duplicate C in 8 bytes of MM1 ** */ + "mov %3, %%al \n\t" /* load C into AL */ + "mov %%al, %%ah \n\t" /* copy AL into AH */ + "mov %%ax, %%bx \n\t" /* copy AX into BX */ + "shl $16, %%eax \n\t" /* shift 2 bytes of EAX left */ + "mov %%bx, %%ax \n\t" /* copy BX into AX */ + "movd %%eax, %%mm1 \n\t" /* copy EAX into MM1 */ + "movd %%eax, %%mm2 \n\t" /* copy EAX into MM2 */ + "punpckldq %%mm2, %%mm1 \n\t" /* fill higher bytes of MM1 with C */ + "mov %1, %%eax \n\t" /* load Src1 address into eax */ + "mov %0, %%edi \n\t" /* load Dest address into edi */ + "mov %2, %%ecx \n\t" /* load loop counter (SIZE) into ecx */ + "shr $3, %%ecx \n\t" /* counter/8 (MMX loads 8 bytes at a time) */ + ".align 16 \n\t" /* 16 byte alignment of the loop entry */ + "1: \n\t" + "movq (%%eax), %%mm0 \n\t" /* load 8 bytes from Src1 into MM0 */ + "paddusb %%mm1, %%mm0 \n\t" /* MM0=SrcDest+C (add 8 bytes with saturation) */ + "movq %%mm0, (%%edi) \n\t" /* store result in Dest */ + "add $8, %%eax \n\t" /* increase Dest register pointer by 8 */ + "add $8, %%edi \n\t" /* increase Dest register pointer by 8 */ + "dec %%ecx \n\t" /* decrease loop counter */ + "jnz 1b \n\t" /* check loop termination, proceed if required */ + "emms \n\t" /* exit MMX state */ + "popa \n\t":"=m" (Dest) /* %0 */ + :"m"(Src1), /* %1 */ + "m"(SrcLength), /* %2 */ + "m"(C) /* %3 */ + ); +#endif + return (0); +#else + return (-1); +#endif +} + +/*! +\brief Filter using AddByte: D = saturation255(S + C) + +\param Src1 Pointer to the start of the source byte array (S). +\param Dest Pointer to the start of the destination byte array (D). +\param length The number of bytes in the source array. +\param C Constant value to add (C). + + +\return Returns 0 for success or -1 for error. +*/ +int SDL_imageFilterAddByte(unsigned char *Src1, unsigned char *Dest, unsigned int length, unsigned char C) +{ + unsigned int i, istart; + int iC; + unsigned char *cursrc1, *curdest; + int result; + + /* Validate input parameters */ + if ((Src1 == NULL) || (Dest == NULL)) + return(-1); + if (length == 0) + return(0); + + /* Special case: C==0 */ + if (C == 0) { + memcpy(Src1, Dest, length); + return (0); + } + + if ((SDL_imageFilterMMXdetect()) && (length > 7)) { + + /* MMX routine */ + SDL_imageFilterAddByteMMX(Src1, Dest, length, C); + + /* Check for unaligned bytes */ + if ((length & 7) > 0) { + /* Setup to process unaligned bytes */ + istart = length & 0xfffffff8; + cursrc1 = &Src1[istart]; + curdest = &Dest[istart]; + } else { + /* No unaligned bytes - we are done */ + return (0); + } + } else { + /* Setup to process whole image */ + istart = 0; + cursrc1 = Src1; + curdest = Dest; + } + + /* C routine to process image */ + iC = (int) C; + for (i = istart; i < length; i++) { + result = (int) *cursrc1 + iC; + if (result > 255) + result = 255; + *curdest = (unsigned char) result; + /* Advance pointers */ + cursrc1++; + curdest++; + } + return (0); +} + +/*! +\brief Internal MMX Filter using AddUint: D = saturation255((S[i] + Cs[i % 4]), Cs=Swap32((uint)C) + +\param Src1 Pointer to the start of the source byte array (S). +\param Dest Pointer to the start of the destination byte array (D). +\param SrcLength The number of bytes in the source array. +\param C Constant to add (C). +\param D Byteorder-swapped constant to add (Cs). + +\return Returns 0 for success or -1 for error. +*/ +int SDL_imageFilterAddUintMMX(unsigned char *Src1, unsigned char *Dest, unsigned int SrcLength, unsigned int C, unsigned int D) +{ +#ifdef USE_MMX +#if !defined(GCC__) + __asm + { + pusha + /* ** Duplicate (int)C in 8 bytes of MM1 ** */ + mov eax, C /* load C into EAX */ + movd mm1, eax /* copy EAX into MM1 */ + mov eax, D /* load D into EAX */ + movd mm2, eax /* copy EAX into MM2 */ + punpckldq mm1, mm2 /* fill higher bytes of MM1 with C */ + mov eax, Src1 /* load Src1 address into eax */ + mov edi, Dest /* load Dest address into edi */ + mov ecx, SrcLength /* load loop counter (SIZE) into ecx */ + shr ecx, 3 /* counter/8 (MMX loads 8 bytes at a time) */ + align 16 /* 16 byte alignment of the loop entry */ +L11023: + movq mm0, [eax] /* load 8 bytes from SrcDest into MM0 */ + paddusb mm0, mm1 /* MM0=SrcDest+C (add 8 bytes with saturation) */ + movq [edi], mm0 /* store result in SrcDest */ + add eax, 8 /* increase Src1 register pointer by 8 */ + add edi, 8 /* increase Dest register pointer by 8 */ + dec ecx /* decrease loop counter */ + jnz L11023 /* check loop termination, proceed if required */ + emms /* exit MMX state */ + popa + } +#else + asm volatile + ("pusha \n\t" + /* ** Duplicate (int)C in 8 bytes of MM1 ** */ + "mov %3, %%eax \n\t" /* load C into EAX */ + "movd %%eax, %%mm1 \n\t" /* copy EAX into MM1 */ + "mov %4, %%eax \n\t" /* load D into EAX */ + "movd %%eax, %%mm2 \n\t" /* copy EAX into MM2 */ + "punpckldq %%mm2, %%mm1 \n\t" /* fill higher bytes of MM1 with C */ + "mov %1, %%eax \n\t" /* load Src1 address into eax */ + "mov %0, %%edi \n\t" /* load Dest address into edi */ + "mov %2, %%ecx \n\t" /* load loop counter (SIZE) into ecx */ + "shr $3, %%ecx \n\t" /* counter/8 (MMX loads 8 bytes at a time) */ + ".align 16 \n\t" /* 16 byte alignment of the loop entry */ + "1: \n\t" + "movq (%%eax), %%mm0 \n\t" /* load 8 bytes from SrcDest into MM0 */ + "paddusb %%mm1, %%mm0 \n\t" /* MM0=SrcDest+C (add 8 bytes with saturation) */ + "movq %%mm0, (%%edi) \n\t" /* store result in SrcDest */ + "add $8, %%eax \n\t" /* increase Src1 register pointer by 8 */ + "add $8, %%edi \n\t" /* increase Dest register pointer by 8 */ + "dec %%ecx \n\t" /* decrease loop counter */ + "jnz 1b \n\t" /* check loop termination, proceed if required */ + "emms \n\t" /* exit MMX state */ + "popa \n\t":"=m" (Dest) /* %0 */ + :"m"(Src1), /* %1 */ + "m"(SrcLength), /* %2 */ + "m"(C), /* %3 */ + "m"(D) /* %4 */ + ); +#endif + return (0); +#else + return (-1); +#endif +} + +/*! +\brief Filter using AddUint: D = saturation255((S[i] + Cs[i % 4]), Cs=Swap32((uint)C) + +\param Src1 Pointer to the start of the source byte array (S). +\param Dest Pointer to the start of the destination byte array (D). +\param length The number of bytes in the source array. +\param C Constant to add (C). + +\return Returns 0 for success or -1 for error. +*/ +int SDL_imageFilterAddUint(unsigned char *Src1, unsigned char *Dest, unsigned int length, unsigned int C) +{ + unsigned int i, j, istart, D; + int iC[4]; + unsigned char *cursrc1; + unsigned char *curdest; + int result; + + /* Validate input parameters */ + if ((Src1 == NULL) || (Dest == NULL)) + return(-1); + if (length == 0) + return(0); + + /* Special case: C==0 */ + if (C == 0) { + memcpy(Src1, Dest, length); + return (0); + } + + if ((SDL_imageFilterMMXdetect()) && (length > 7)) { + + /* MMX routine */ + D=SWAP_32(C); + SDL_imageFilterAddUintMMX(Src1, Dest, length, C, D); + + /* Check for unaligned bytes */ + if ((length & 7) > 0) { + /* Setup to process unaligned bytes */ + istart = length & 0xfffffff8; + cursrc1 = &Src1[istart]; + curdest = &Dest[istart]; + } else { + /* No unaligned bytes - we are done */ + return (0); + } + } else { + /* Setup to process whole image */ + istart = 0; + cursrc1 = Src1; + curdest = Dest; + } + + /* C routine to process bytes */ + iC[3] = (int) ((C >> 24) & 0xff); + iC[2] = (int) ((C >> 16) & 0xff); + iC[1] = (int) ((C >> 8) & 0xff); + iC[0] = (int) ((C >> 0) & 0xff); + for (i = istart; i < length; i += 4) { + for (j = 0; j < 4; j++) { + if ((i+j) 255) result = 255; + *curdest = (unsigned char) result; + /* Advance pointers */ + cursrc1++; + curdest++; + } + } + } + return (0); +} + +/*! +\brief Internal MMX Filter using AddByteToHalf: D = saturation255(S/2 + C) + +\param Src1 Pointer to the start of the source byte array (S). +\param Dest Pointer to the start of the destination byte array (D). +\param SrcLength The number of bytes in the source array. +\param C Constant to add (C). +\param Mask Pointer to 8 mask bytes of value 0x7F. + +\return Returns 0 for success or -1 for error. +*/ +int SDL_imageFilterAddByteToHalfMMX(unsigned char *Src1, unsigned char *Dest, unsigned int SrcLength, unsigned char C, + unsigned char *Mask) +{ +#ifdef USE_MMX +#if !defined(GCC__) + __asm + { + pusha + /* ** Duplicate C in 8 bytes of MM1 ** */ + mov al, C /* load C into AL */ + mov ah, al /* copy AL into AH */ + mov bx, ax /* copy AX into BX */ + shl eax, 16 /* shift 2 bytes of EAX left */ + mov ax, bx /* copy BX into AX */ + movd mm1, eax /* copy EAX into MM1 */ + movd mm2, eax /* copy EAX into MM2 */ + punpckldq mm1, mm2 /* fill higher bytes of MM1 with C */ + mov edx, Mask /* load Mask address into edx */ + movq mm0, [edx] /* load Mask into mm0 */ + mov eax, Src1 /* load Src1 address into eax */ + mov edi, Dest /* load Dest address into edi */ + mov ecx, SrcLength /* load loop counter (SIZE) into ecx */ + shr ecx, 3 /* counter/8 (MMX loads 8 bytes at a time) */ + align 16 /* 16 byte alignment of the loop entry */ +L1022: + movq mm2, [eax] /* load 8 bytes from Src1 into MM2 */ + psrlw mm2, 1 /* shift 4 WORDS of MM2 1 bit to the right */ + pand mm2, mm0 // apply Mask to 8 BYTES of MM2 */ + /* byte 0x0f, 0xdb, 0xd0 */ + paddusb mm2, mm1 /* MM2=SrcDest+C (add 8 bytes with saturation) */ + movq [edi], mm2 /* store result in Dest */ + add eax, 8 /* increase Src1 register pointer by 8 */ + add edi, 8 /* increase Dest register pointer by 8 */ + dec ecx /* decrease loop counter */ + jnz L1022 /* check loop termination, proceed if required */ + emms /* exit MMX state */ + popa + } +#else + asm volatile + ("pusha \n\t" + /* ** Duplicate C in 8 bytes of MM1 ** */ + "mov %3, %%al \n\t" /* load C into AL */ + "mov %%al, %%ah \n\t" /* copy AL into AH */ + "mov %%ax, %%bx \n\t" /* copy AX into BX */ + "shl $16, %%eax \n\t" /* shift 2 bytes of EAX left */ + "mov %%bx, %%ax \n\t" /* copy BX into AX */ + "movd %%eax, %%mm1 \n\t" /* copy EAX into MM1 */ + "movd %%eax, %%mm2 \n\t" /* copy EAX into MM2 */ + "punpckldq %%mm2, %%mm1 \n\t" /* fill higher bytes of MM1 with C */ + "movl %4, %%edx \n\t" /* load Mask address into edx */ + "movq (%%edx), %%mm0 \n\t" /* load Mask into mm0 */ + "mov %1, %%eax \n\t" /* load Src1 address into eax */ + "mov %0, %%edi \n\t" /* load Dest address into edi */ + "mov %2, %%ecx \n\t" /* load loop counter (SIZE) into ecx */ + "shr $3, %%ecx \n\t" /* counter/8 (MMX loads 8 bytes at a time) */ + ".align 16 \n\t" /* 16 byte alignment of the loop entry */ + "1: \n\t" + "movq (%%eax), %%mm2 \n\t" /* load 8 bytes from Src1 into MM2 */ + "psrlw $1, %%mm2 \n\t" /* shift 4 WORDS of MM2 1 bit to the right */ + /* "pand %%mm0, %%mm2 \n\t" // apply Mask to 8 BYTES of MM2 */ + ".byte 0x0f, 0xdb, 0xd0 \n\t" + "paddusb %%mm1, %%mm2 \n\t" /* MM2=SrcDest+C (add 8 bytes with saturation) */ + "movq %%mm2, (%%edi) \n\t" /* store result in Dest */ + "add $8, %%eax \n\t" /* increase Src1 register pointer by 8 */ + "add $8, %%edi \n\t" /* increase Dest register pointer by 8 */ + "dec %%ecx \n\t" /* decrease loop counter */ + "jnz 1b \n\t" /* check loop termination, proceed if required */ + "emms \n\t" /* exit MMX state */ + "popa \n\t":"=m" (Dest) /* %0 */ + :"m"(Src1), /* %1 */ + "m"(SrcLength), /* %2 */ + "m"(C), /* %3 */ + "m"(Mask) /* %4 */ + ); +#endif + return (0); +#else + return (-1); +#endif +} + +/*! +\brief Filter using AddByteToHalf: D = saturation255(S/2 + C) + +\param Src1 Pointer to the start of the source byte array (S). +\param Dest Pointer to the start of the destination byte array (D). +\param length The number of bytes in the source array. +\param C Constant to add (C). + +\return Returns 0 for success or -1 for error. +*/ +int SDL_imageFilterAddByteToHalf(unsigned char *Src1, unsigned char *Dest, unsigned int length, unsigned char C) +{ + static unsigned char Mask[8] = { 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F }; + unsigned int i, istart; + int iC; + unsigned char *cursrc1; + unsigned char *curdest; + int result; + + /* Validate input parameters */ + if ((Src1 == NULL) || (Dest == NULL)) + return(-1); + if (length == 0) + return(0); + + if ((SDL_imageFilterMMXdetect()) && (length > 7)) { + + /* MMX routine */ + SDL_imageFilterAddByteToHalfMMX(Src1, Dest, length, C, Mask); + + /* Check for unaligned bytes */ + if ((length & 7) > 0) { + /* Setup to process unaligned bytes */ + istart = length & 0xfffffff8; + cursrc1 = &Src1[istart]; + curdest = &Dest[istart]; + } else { + /* No unaligned bytes - we are done */ + return (0); + } + } else { + /* Setup to process whole image */ + istart = 0; + cursrc1 = Src1; + curdest = Dest; + } + + /* C routine to process image */ + iC = (int) C; + for (i = istart; i < length; i++) { + result = (int) (*cursrc1 / 2) + iC; + if (result > 255) + result = 255; + *curdest = (unsigned char) result; + /* Advance pointers */ + cursrc1++; + curdest++; + } + + return (0); +} + +/*! +\brief Internal MMX Filter using SubByte: D = saturation0(S - C) + +\param Src1 Pointer to the start of the source byte array (S). +\param Dest Pointer to the start of the destination byte array (D). +\param SrcLength The number of bytes in the source array. +\param C Constant to subtract (C). + +\return Returns 0 for success or -1 for error. +*/ +int SDL_imageFilterSubByteMMX(unsigned char *Src1, unsigned char *Dest, unsigned int SrcLength, unsigned char C) +{ +#ifdef USE_MMX +#if !defined(GCC__) + __asm + { + pusha + /* ** Duplicate C in 8 bytes of MM1 ** */ + mov al, C /* load C into AL */ + mov ah, al /* copy AL into AH */ + mov bx, ax /* copy AX into BX */ + shl eax, 16 /* shift 2 bytes of EAX left */ + mov ax, bx /* copy BX into AX */ + movd mm1, eax /* copy EAX into MM1 */ + movd mm2, eax /* copy EAX into MM2 */ + punpckldq mm1, mm2 /* fill higher bytes of MM1 with C */ + mov eax, Src1 /* load Src1 address into eax */ + mov edi, Dest /* load Dest address into edi */ + mov ecx, SrcLength /* load loop counter (SIZE) into ecx */ + shr ecx, 3 /* counter/8 (MMX loads 8 bytes at a time) */ + align 16 /* 16 byte alignment of the loop entry */ +L1023: + movq mm0, [eax] /* load 8 bytes from SrcDest into MM0 */ + psubusb mm0, mm1 /* MM0=SrcDest-C (sub 8 bytes with saturation) */ + movq [edi], mm0 /* store result in SrcDest */ + add eax, 8 /* increase Src1 register pointer by 8 */ + add edi, 8 /* increase Dest register pointer by 8 */ + dec ecx /* decrease loop counter */ + jnz L1023 /* check loop termination, proceed if required */ + emms /* exit MMX state */ + popa + } +#else + asm volatile + ("pusha \n\t" + /* ** Duplicate C in 8 bytes of MM1 ** */ + "mov %3, %%al \n\t" /* load C into AL */ + "mov %%al, %%ah \n\t" /* copy AL into AH */ + "mov %%ax, %%bx \n\t" /* copy AX into BX */ + "shl $16, %%eax \n\t" /* shift 2 bytes of EAX left */ + "mov %%bx, %%ax \n\t" /* copy BX into AX */ + "movd %%eax, %%mm1 \n\t" /* copy EAX into MM1 */ + "movd %%eax, %%mm2 \n\t" /* copy EAX into MM2 */ + "punpckldq %%mm2, %%mm1 \n\t" /* fill higher bytes of MM1 with C */ + "mov %1, %%eax \n\t" /* load Src1 address into eax */ + "mov %0, %%edi \n\t" /* load Dest address into edi */ + "mov %2, %%ecx \n\t" /* load loop counter (SIZE) into ecx */ + "shr $3, %%ecx \n\t" /* counter/8 (MMX loads 8 bytes at a time) */ + ".align 16 \n\t" /* 16 byte alignment of the loop entry */ + "1: movq (%%eax), %%mm0 \n\t" /* load 8 bytes from SrcDest into MM0 */ + "psubusb %%mm1, %%mm0 \n\t" /* MM0=SrcDest-C (sub 8 bytes with saturation) */ + "movq %%mm0, (%%edi) \n\t" /* store result in SrcDest */ + "add $8, %%eax \n\t" /* increase Src1 register pointer by 8 */ + "add $8, %%edi \n\t" /* increase Dest register pointer by 8 */ + "dec %%ecx \n\t" /* decrease loop counter */ + "jnz 1b \n\t" /* check loop termination, proceed if required */ + "emms \n\t" /* exit MMX state */ + "popa \n\t":"=m" (Dest) /* %0 */ + :"m"(Src1), /* %1 */ + "m"(SrcLength), /* %2 */ + "m"(C) /* %3 */ + ); +#endif + return (0); +#else + return (-1); +#endif +} + +/*! +\brief Filter using SubByte: D = saturation0(S - C) + +\param Src1 Pointer to the start of the source byte array (S). +\param Dest Pointer to the start of the destination byte array (D). +\param length The number of bytes in the source arrays. +\param C Constant to subtract (C). + +\return Returns 0 for success or -1 for error. +*/ +int SDL_imageFilterSubByte(unsigned char *Src1, unsigned char *Dest, unsigned int length, unsigned char C) +{ + unsigned int i, istart; + int iC; + unsigned char *cursrc1; + unsigned char *curdest; + int result; + + /* Validate input parameters */ + if ((Src1 == NULL) || (Dest == NULL)) + return(-1); + if (length == 0) + return(0); + + /* Special case: C==0 */ + if (C == 0) { + memcpy(Src1, Dest, length); + return (0); + } + + if ((SDL_imageFilterMMXdetect()) && (length > 7)) { + + /* MMX routine */ + SDL_imageFilterSubByteMMX(Src1, Dest, length, C); + + /* Check for unaligned bytes */ + if ((length & 7) > 0) { + /* Setup to process unaligned bytes */ + istart = length & 0xfffffff8; + cursrc1 = &Src1[istart]; + curdest = &Dest[istart]; + } else { + /* No unaligned bytes - we are done */ + return (0); + } + } else { + /* Setup to process whole image */ + istart = 0; + cursrc1 = Src1; + curdest = Dest; + } + + /* C routine to process image */ + iC = (int) C; + for (i = istart; i < length; i++) { + result = (int) *cursrc1 - iC; + if (result < 0) + result = 0; + *curdest = (unsigned char) result; + /* Advance pointers */ + cursrc1++; + curdest++; + } + return (0); +} + +/*! +\brief Internal MMX Filter using SubUint: D = saturation0(S[i] - Cs[i % 4]), Cs=Swap32((uint)C) + +\param Src1 Pointer to the start of the source byte array (S). +\param Dest Pointer to the start of the destination byte array (D). +\param SrcLength The number of bytes in the source array. +\param C Constant to subtract (C). +\param D Byteorder-swapped constant to subtract (Cs). + +\return Returns 0 for success or -1 for error. +*/ +int SDL_imageFilterSubUintMMX(unsigned char *Src1, unsigned char *Dest, unsigned int SrcLength, unsigned int C, unsigned int D) +{ +#ifdef USE_MMX +#if !defined(GCC__) + __asm + { + pusha + /* ** Duplicate (int)C in 8 bytes of MM1 ** */ + mov eax, C /* load C into EAX */ + movd mm1, eax /* copy EAX into MM1 */ + mov eax, D /* load D into EAX */ + movd mm2, eax /* copy EAX into MM2 */ + punpckldq mm1, mm2 /* fill higher bytes of MM1 with C */ + mov eax, Src1 /* load Src1 address into eax */ + mov edi, Dest /* load Dest address into edi */ + mov ecx, SrcLength /* load loop counter (SIZE) into ecx */ + shr ecx, 3 /* counter/8 (MMX loads 8 bytes at a time) */ + align 16 /* 16 byte alignment of the loop entry */ +L11024: + movq mm0, [eax] /* load 8 bytes from SrcDest into MM0 */ + psubusb mm0, mm1 /* MM0=SrcDest-C (sub 8 bytes with saturation) */ + movq [edi], mm0 /* store result in SrcDest */ + add eax, 8 /* increase Src1 register pointer by 8 */ + add edi, 8 /* increase Dest register pointer by 8 */ + dec ecx /* decrease loop counter */ + jnz L11024 /* check loop termination, proceed if required */ + emms /* exit MMX state */ + popa + } +#else + asm volatile + ("pusha \n\t" + /* ** Duplicate (int)C in 8 bytes of MM1 ** */ + "mov %3, %%eax \n\t" /* load C into EAX */ + "movd %%eax, %%mm1 \n\t" /* copy EAX into MM1 */ + "mov %4, %%eax \n\t" /* load D into EAX */ + "movd %%eax, %%mm2 \n\t" /* copy EAX into MM2 */ + "punpckldq %%mm2, %%mm1 \n\t" /* fill higher bytes of MM1 with C */ + "mov %1, %%eax \n\t" /* load Src1 address into eax */ + "mov %0, %%edi \n\t" /* load Dest address into edi */ + "mov %2, %%ecx \n\t" /* load loop counter (SIZE) into ecx */ + "shr $3, %%ecx \n\t" /* counter/8 (MMX loads 8 bytes at a time) */ + ".align 16 \n\t" /* 16 byte alignment of the loop entry */ + "1: movq (%%eax), %%mm0 \n\t" /* load 8 bytes from SrcDest into MM0 */ + "psubusb %%mm1, %%mm0 \n\t" /* MM0=SrcDest-C (sub 8 bytes with saturation) */ + "movq %%mm0, (%%edi) \n\t" /* store result in SrcDest */ + "add $8, %%eax \n\t" /* increase Src1 register pointer by 8 */ + "add $8, %%edi \n\t" /* increase Dest register pointer by 8 */ + "dec %%ecx \n\t" /* decrease loop counter */ + "jnz 1b \n\t" /* check loop termination, proceed if required */ + "emms \n\t" /* exit MMX state */ + "popa \n\t":"=m" (Dest) /* %0 */ + :"m"(Src1), /* %1 */ + "m"(SrcLength), /* %2 */ + "m"(C), /* %3 */ + "m"(D) /* %4 */ + ); +#endif + return (0); +#else + return (-1); +#endif +} + +/*! +\brief Filter using SubUint: D = saturation0(S[i] - Cs[i % 4]), Cs=Swap32((uint)C) + +\param Src1 Pointer to the start of the source byte array (S1). +\param Dest Pointer to the start of the destination byte array (D). +\param length The number of bytes in the source array. +\param C Constant to subtract (C). + +\return Returns 0 for success or -1 for error. +*/ +int SDL_imageFilterSubUint(unsigned char *Src1, unsigned char *Dest, unsigned int length, unsigned int C) +{ + unsigned int i, j, istart, D; + int iC[4]; + unsigned char *cursrc1; + unsigned char *curdest; + int result; + + /* Validate input parameters */ + if ((Src1 == NULL) || (Dest == NULL)) + return(-1); + if (length == 0) + return(0); + + /* Special case: C==0 */ + if (C == 0) { + memcpy(Src1, Dest, length); + return (0); + } + + if ((SDL_imageFilterMMXdetect()) && (length > 7)) { + + /* MMX routine */ + D=SWAP_32(C); + SDL_imageFilterSubUintMMX(Src1, Dest, length, C, D); + + /* Check for unaligned bytes */ + if ((length & 7) > 0) { + /* Setup to process unaligned bytes */ + istart = length & 0xfffffff8; + cursrc1 = &Src1[istart]; + curdest = &Dest[istart]; + } else { + /* No unaligned bytes - we are done */ + return (0); + } + } else { + /* Setup to process whole image */ + istart = 0; + cursrc1 = Src1; + curdest = Dest; + } + + /* C routine to process image */ + iC[3] = (int) ((C >> 24) & 0xff); + iC[2] = (int) ((C >> 16) & 0xff); + iC[1] = (int) ((C >> 8) & 0xff); + iC[0] = (int) ((C >> 0) & 0xff); + for (i = istart; i < length; i += 4) { + for (j = 0; j < 4; j++) { + if ((i+j)> N) + +\param Src1 Pointer to the start of the source byte array (S). +\param Dest Pointer to the start of the destination byte array (D). +\param SrcLength The number of bytes in the source array. +\param N Number of bit-positions to shift (N). Valid range is 0 to 8. +\param Mask Byte array containing 8 bytes with 0x7F value. + +\return Returns 0 for success or -1 for error. +*/ +int SDL_imageFilterShiftRightMMX(unsigned char *Src1, unsigned char *Dest, unsigned int SrcLength, unsigned char N, + unsigned char *Mask) +{ +#ifdef USE_MMX +#if !defined(GCC__) + __asm + { + pusha + mov edx, Mask /* load Mask address into edx */ + movq mm0, [edx] /* load Mask into mm0 */ + xor ecx, ecx /* zero ECX */ + mov cl, N /* load loop counter (N) into CL */ + movd mm3, ecx /* copy (N) into MM3 */ + pcmpeqb mm1, mm1 /* generate all 1's in mm1 */ +L10240: /* ** Prepare proper bit-Mask in MM1 ** */ + psrlw mm1, 1 /* shift 4 WORDS of MM1 1 bit to the right */ + pand mm1, mm0 // apply Mask to 8 BYTES of MM1 */ + /* byte 0x0f, 0xdb, 0xc8 */ + dec cl /* decrease loop counter */ + jnz L10240 /* check loop termination, proceed if required */ + /* ** Shift all bytes of the image ** */ + mov eax, Src1 /* load Src1 address into eax */ + mov edi, Dest /* load Dest address into edi */ + mov ecx, SrcLength /* load loop counter (SIZE) into ecx */ + shr ecx, 3 /* counter/8 (MMX loads 8 bytes at a time) */ + align 16 /* 16 byte alignment of the loop entry */ +L10241: + movq mm0, [eax] /* load 8 bytes from SrcDest into MM0 */ + psrlw mm0, mm3 /* shift 4 WORDS of MM0 (N) bits to the right */ + pand mm0, mm1 // apply proper bit-Mask to 8 BYTES of MM0 */ + /* byte 0x0f, 0xdb, 0xc1 */ + movq [edi], mm0 /* store result in SrcDest */ + add eax, 8 /* increase Src1 register pointer by 8 */ + add edi, 8 /* increase Dest register pointer by 8 */ + dec ecx /* decrease loop counter */ + jnz L10241 /* check loop termination, proceed if required */ + emms /* exit MMX state */ + popa + } +#else + asm volatile + ("pusha \n\t" "movl %4, %%edx \n\t" /* load Mask address into edx */ + "movq (%%edx), %%mm0 \n\t" /* load Mask into mm0 */ + "xor %%ecx, %%ecx \n\t" /* zero ECX */ + "mov %3, %%cl \n\t" /* load loop counter (N) into CL */ + "movd %%ecx, %%mm3 \n\t" /* copy (N) into MM3 */ + "pcmpeqb %%mm1, %%mm1 \n\t" /* generate all 1's in mm1 */ + "1: \n\t" /* ** Prepare proper bit-Mask in MM1 ** */ + "psrlw $1, %%mm1 \n\t" /* shift 4 WORDS of MM1 1 bit to the right */ + /* "pand %%mm0, %%mm1 \n\t" // apply Mask to 8 BYTES of MM1 */ + ".byte 0x0f, 0xdb, 0xc8 \n\t" + "dec %%cl \n\t" /* decrease loop counter */ + "jnz 1b \n\t" /* check loop termination, proceed if required */ + /* ** Shift all bytes of the image ** */ + "mov %1, %%eax \n\t" /* load Src1 address into eax */ + "mov %0, %%edi \n\t" /* load Dest address into edi */ + "mov %2, %%ecx \n\t" /* load loop counter (SIZE) into ecx */ + "shr $3, %%ecx \n\t" /* counter/8 (MMX loads 8 bytes at a time) */ + ".align 16 \n\t" /* 16 byte alignment of the loop entry */ + "2: \n\t" + "movq (%%eax), %%mm0 \n\t" /* load 8 bytes from SrcDest into MM0 */ + "psrlw %%mm3, %%mm0 \n\t" /* shift 4 WORDS of MM0 (N) bits to the right */ + /* "pand %%mm1, %%mm0 \n\t" // apply proper bit-Mask to 8 BYTES of MM0 */ + ".byte 0x0f, 0xdb, 0xc1 \n\t" + "movq %%mm0, (%%edi) \n\t" /* store result in SrcDest */ + "add $8, %%eax \n\t" /* increase Src1 register pointer by 8 */ + "add $8, %%edi \n\t" /* increase Dest register pointer by 8 */ + "dec %%ecx \n\t" /* decrease loop counter */ + "jnz 2b \n\t" /* check loop termination, proceed if required */ + "emms \n\t" /* exit MMX state */ + "popa \n\t":"=m" (Dest) /* %0 */ + :"m"(Src1), /* %1 */ + "m"(SrcLength), /* %2 */ + "m"(N), /* %3 */ + "m"(Mask) /* %4 */ + ); +#endif + return (0); +#else + return (-1); +#endif +} + +/*! +\brief Filter using ShiftRight: D = saturation0(S >> N) + +\param Src1 Pointer to the start of the source byte array (S). +\param Dest Pointer to the start of the destination byte array (D). +\param length The number of bytes in the source array. +\param N Number of bit-positions to shift (N). Valid range is 0 to 8. + +\return Returns 0 for success or -1 for error. +*/ +int SDL_imageFilterShiftRight(unsigned char *Src1, unsigned char *Dest, unsigned int length, unsigned char N) +{ + static unsigned char Mask[8] = { 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F }; + unsigned int i, istart; + unsigned char *cursrc1; + unsigned char *curdest; + + /* Validate input parameters */ + if ((Src1 == NULL) || (Dest == NULL)) + return(-1); + if (length == 0) + return(0); + + /* Check shift */ + if (N > 8) { + return (-1); + } + + /* Special case: N==0 */ + if (N == 0) { + memcpy(Src1, Dest, length); + return (0); + } + + if ((SDL_imageFilterMMXdetect()) && (length > 7)) { + + /* MMX routine */ + SDL_imageFilterShiftRightMMX(Src1, Dest, length, N, Mask); + + /* Check for unaligned bytes */ + if ((length & 7) > 0) { + /* Setup to process unaligned bytes */ + istart = length & 0xfffffff8; + cursrc1 = &Src1[istart]; + curdest = &Dest[istart]; + } else { + /* No unaligned bytes - we are done */ + return (0); + } + } else { + /* Setup to process whole image */ + istart = 0; + cursrc1 = Src1; + curdest = Dest; + } + + /* C routine to process image */ + for (i = istart; i < length; i++) { + *curdest = (unsigned char) *cursrc1 >> N; + /* Advance pointers */ + cursrc1++; + curdest++; + } + + return (0); +} + +/*! +\brief Internal MMX Filter using ShiftRightUint: D = saturation0((uint)S[i] >> N) + +\param Src1 Pointer to the start of the source byte array (S1). +\param Dest Pointer to the start of the destination byte array (D). +\param SrcLength The number of bytes in the source array. +\param N Number of bit-positions to shift (N). + +\return Returns 0 for success or -1 for error. +*/ +int SDL_imageFilterShiftRightUintMMX(unsigned char *Src1, unsigned char *Dest, unsigned int SrcLength, unsigned char N) +{ +#ifdef USE_MMX +#if !defined(GCC__) + __asm + { + pusha + mov eax, Src1 /* load Src1 address into eax */ + mov edi, Dest /* load Dest address into edi */ + mov ecx, SrcLength /* load loop counter (SIZE) into ecx */ + shr ecx, 3 /* counter/8 (MMX loads 8 bytes at a time) */ + align 16 /* 16 byte alignment of the loop entry */ +L13023: + movq mm0, [eax] /* load 8 bytes from SrcDest into MM0 */ + psrld mm0, N + movq [edi], mm0 /* store result in SrcDest */ + add eax, 8 /* increase Src1 register pointer by 8 */ + add edi, 8 /* increase Dest register pointer by 8 */ + dec ecx /* decrease loop counter */ + jnz L13023 /* check loop termination, proceed if required */ + emms /* exit MMX state */ + popa + } +#else + asm volatile + ("pusha \n\t" + "mov %1, %%eax \n\t" /* load Src1 address into eax */ + "mov %0, %%edi \n\t" /* load Dest address into edi */ + "mov %2, %%ecx \n\t" /* load loop counter (SIZE) into ecx */ + "shr $3, %%ecx \n\t" /* counter/8 (MMX loads 8 bytes at a time) */ + ".align 16 \n\t" /* 16 byte alignment of the loop entry */ + "1: movq (%%eax), %%mm0 \n\t" /* load 8 bytes from SrcDest into MM0 */ + "psrld %3, %%mm0 \n\t" + "movq %%mm0, (%%edi) \n\t" /* store result in SrcDest */ + "add $8, %%eax \n\t" /* increase Src1 register pointer by 8 */ + "add $8, %%edi \n\t" /* increase Dest register pointer by 8 */ + "dec %%ecx \n\t" /* decrease loop counter */ + "jnz 1b \n\t" /* check loop termination, proceed if required */ + "emms \n\t" /* exit MMX state */ + "popa \n\t":"=m" (Dest) /* %0 */ + :"m"(Src1), /* %1 */ + "m"(SrcLength), /* %2 */ + "m"(N) /* %3 */ + ); +#endif + return (0); +#else + return (-1); +#endif +} + +/*! +\brief Filter using ShiftRightUint: D = saturation0((uint)S[i] >> N) + +\param Src1 Pointer to the start of the source byte array (S1). +\param Dest Pointer to the start of the destination byte array (D). +\param length The number of bytes in the source array. +\param N Number of bit-positions to shift (N). Valid range is 0 to 32. + +\return Returns 0 for success or -1 for error. +*/ +int SDL_imageFilterShiftRightUint(unsigned char *Src1, unsigned char *Dest, unsigned int length, unsigned char N) +{ + unsigned int i, istart; + unsigned char *cursrc1, *curdest; + unsigned int *icursrc1, *icurdest; + int result; + + /* Validate input parameters */ + if ((Src1 == NULL) || (Dest == NULL)) + return(-1); + if (length == 0) + return(0); + + if (N > 32) { + return (-1); + } + + /* Special case: N==0 */ + if (N == 0) { + memcpy(Src1, Dest, length); + return (0); + } + + if ((SDL_imageFilterMMXdetect()) && (length > 7)) { + + SDL_imageFilterShiftRightUintMMX(Src1, Dest, length, N); + + /* Check for unaligned bytes */ + if ((length & 7) > 0) { + /* Setup to process unaligned bytes */ + istart = length & 0xfffffff8; + cursrc1 = &Src1[istart]; + curdest = &Dest[istart]; + } else { + /* No unaligned bytes - we are done */ + return (0); + } + } else { + /* Setup to process whole image */ + istart = 0; + cursrc1 = Src1; + curdest = Dest; + } + + /* C routine to process image */ + icursrc1=(unsigned int *)cursrc1; + icurdest=(unsigned int *)curdest; + for (i = istart; i < length; i += 4) { + if ((i+4)> N); + *icurdest = (unsigned int)result; + } + /* Advance pointers */ + icursrc1++; + icurdest++; + } + + return (0); +} + +/*! +\brief Internal MMX Filter using MultByByte: D = saturation255(S * C) + +\param Src1 Pointer to the start of the source byte array (S). +\param Dest Pointer to the start of the destination byte array (D). +\param SrcLength The number of bytes in the source array. +\param C Constant to multiply with (C). + +\return Returns 0 for success or -1 for error. +*/ +int SDL_imageFilterMultByByteMMX(unsigned char *Src1, unsigned char *Dest, unsigned int SrcLength, unsigned char C) +{ +#ifdef USE_MMX +#if !defined(GCC__) + __asm + { + pusha + /* ** Duplicate C in 4 words of MM1 ** */ + mov al, C /* load C into AL */ + xor ah, ah /* zero AH */ + mov bx, ax /* copy AX into BX */ + shl eax, 16 /* shift 2 bytes of EAX left */ + mov ax, bx /* copy BX into AX */ + movd mm1, eax /* copy EAX into MM1 */ + movd mm2, eax /* copy EAX into MM2 */ + punpckldq mm1, mm2 /* fill higher words of MM1 with C */ + pxor mm0, mm0 /* zero MM0 register */ + mov eax, Src1 /* load Src1 address into eax */ + mov edi, Dest /* load Dest address into edi */ + mov ecx, SrcLength /* load loop counter (SIZE) into ecx */ + shr ecx, 3 /* counter/8 (MMX loads 8 bytes at a time) */ + cmp al, 128 /* if (C <= 128) execute more efficient code */ + jg L10251 + align 16 /* 16 byte alignment of the loop entry */ +L10250: + movq mm3, [eax] /* load 8 bytes from Src1 into MM3 */ + movq mm4, mm3 /* copy MM3 into MM4 */ + punpcklbw mm3, mm0 /* unpack low bytes of SrcDest into words */ + punpckhbw mm4, mm0 /* unpack high bytes of SrcDest into words */ + pmullw mm3, mm1 /* mul low bytes of SrcDest and MM1 */ + pmullw mm4, mm1 /* mul high bytes of SrcDest and MM1 */ + packuswb mm3, mm4 /* pack words back into bytes with saturation */ + movq [edi], mm3 /* store result in Dest */ + add eax, 8 /* increase Src1 register pointer by 8 */ + add edi, 8 /* increase Dest register pointer by 8 */ + dec ecx /* decrease loop counter */ + jnz L10250 /* check loop termination, proceed if required */ + jmp L10252 + align 16 /* 16 byte alignment of the loop entry */ +L10251: + movq mm3, [eax] /* load 8 bytes from Src1 into MM3 */ + movq mm4, mm3 /* copy MM3 into MM4 */ + punpcklbw mm3, mm0 /* unpack low bytes of SrcDest into words */ + punpckhbw mm4, mm0 /* unpack high bytes of SrcDest into words */ + pmullw mm3, mm1 /* mul low bytes of SrcDest and MM1 */ + pmullw mm4, mm1 /* mul high bytes of SrcDest and MM1 */ + /* ** Take abs value of the results (signed words) ** */ + movq mm5, mm3 /* copy mm3 into mm5 */ + movq mm6, mm4 /* copy mm4 into mm6 */ + psraw mm5, 15 /* fill mm5 words with word sign bit */ + psraw mm6, 15 /* fill mm6 words with word sign bit */ + pxor mm3, mm5 /* take 1's compliment of only neg words */ + pxor mm4, mm6 /* take 1's compliment of only neg words */ + psubsw mm3, mm5 /* add 1 to only neg words, W-(-1) or W-0 */ + psubsw mm4, mm6 /* add 1 to only neg words, W-(-1) or W-0 */ + packuswb mm3, mm4 /* pack words back into bytes with saturation */ + movq [edi], mm3 /* store result in Dest */ + add eax, 8 /* increase Src1 register pointer by 8 */ + add edi, 8 /* increase Dest register pointer by 8 */ + dec ecx /* decrease loop counter */ + jnz L10251 /* check loop termination, proceed if required */ +L10252: + emms /* exit MMX state */ + popa + } +#else + asm volatile + ("pusha \n\t" + /* ** Duplicate C in 4 words of MM1 ** */ + "mov %3, %%al \n\t" /* load C into AL */ + "xor %%ah, %%ah \n\t" /* zero AH */ + "mov %%ax, %%bx \n\t" /* copy AX into BX */ + "shl $16, %%eax \n\t" /* shift 2 bytes of EAX left */ + "mov %%bx, %%ax \n\t" /* copy BX into AX */ + "movd %%eax, %%mm1 \n\t" /* copy EAX into MM1 */ + "movd %%eax, %%mm2 \n\t" /* copy EAX into MM2 */ + "punpckldq %%mm2, %%mm1 \n\t" /* fill higher words of MM1 with C */ + "pxor %%mm0, %%mm0 \n\t" /* zero MM0 register */ + "mov %1, %%eax \n\t" /* load Src1 address into eax */ + "mov %0, %%edi \n\t" /* load Dest address into edi */ + "mov %2, %%ecx \n\t" /* load loop counter (SIZE) into ecx */ + "shr $3, %%ecx \n\t" /* counter/8 (MMX loads 8 bytes at a time) */ + "cmp $128, %%al \n\t" /* if (C <= 128) execute more efficient code */ + "jg 2f \n\t" ".align 16 \n\t" /* 16 byte alignment of the loop entry */ + "1: movq (%%eax), %%mm3 \n\t" /* load 8 bytes from Src1 into MM3 */ + "movq %%mm3, %%mm4 \n\t" /* copy MM3 into MM4 */ + "punpcklbw %%mm0, %%mm3 \n\t" /* unpack low bytes of SrcDest into words */ + "punpckhbw %%mm0, %%mm4 \n\t" /* unpack high bytes of SrcDest into words */ + "pmullw %%mm1, %%mm3 \n\t" /* mul low bytes of SrcDest and MM1 */ + "pmullw %%mm1, %%mm4 \n\t" /* mul high bytes of SrcDest and MM1 */ + "packuswb %%mm4, %%mm3 \n\t" /* pack words back into bytes with saturation */ + "movq %%mm3, (%%edi) \n\t" /* store result in Dest */ + "add $8, %%eax \n\t" /* increase Src1 register pointer by 8 */ + "add $8, %%edi \n\t" /* increase Dest register pointer by 8 */ + "dec %%ecx \n\t" /* decrease loop counter */ + "jnz 1b \n\t" /* check loop termination, proceed if required */ + "jmp 3f \n\t" ".align 16 \n\t" /* 16 byte alignment of the loop entry */ + "2: movq (%%eax), %%mm3 \n\t" /* load 8 bytes from Src1 into MM3 */ + "movq %%mm3, %%mm4 \n\t" /* copy MM3 into MM4 */ + "punpcklbw %%mm0, %%mm3 \n\t" /* unpack low bytes of SrcDest into words */ + "punpckhbw %%mm0, %%mm4 \n\t" /* unpack high bytes of SrcDest into words */ + "pmullw %%mm1, %%mm3 \n\t" /* mul low bytes of SrcDest and MM1 */ + "pmullw %%mm1, %%mm4 \n\t" /* mul high bytes of SrcDest and MM1 */ + /* ** Take abs value of the results (signed words) ** */ + "movq %%mm3, %%mm5 \n\t" /* copy mm3 into mm5 */ + "movq %%mm4, %%mm6 \n\t" /* copy mm4 into mm6 */ + "psraw $15, %%mm5 \n\t" /* fill mm5 words with word sign bit */ + "psraw $15, %%mm6 \n\t" /* fill mm6 words with word sign bit */ + "pxor %%mm5, %%mm3 \n\t" /* take 1's compliment of only neg. words */ + "pxor %%mm6, %%mm4 \n\t" /* take 1's compliment of only neg. words */ + "psubsw %%mm5, %%mm3 \n\t" /* add 1 to only neg. words, W-(-1) or W-0 */ + "psubsw %%mm6, %%mm4 \n\t" /* add 1 to only neg. words, W-(-1) or W-0 */ + "packuswb %%mm4, %%mm3 \n\t" /* pack words back into bytes with saturation */ + "movq %%mm3, (%%edi) \n\t" /* store result in Dest */ + "add $8, %%eax \n\t" /* increase Src1 register pointer by 8 */ + "add $8, %%edi \n\t" /* increase Dest register pointer by 8 */ + "dec %%ecx \n\t" /* decrease loop counter */ + "jnz 2b \n\t" /* check loop termination, proceed if required */ + "3: emms \n\t" /* exit MMX state */ + "popa \n\t":"=m" (Dest) /* %0 */ + :"m"(Src1), /* %1 */ + "m"(SrcLength), /* %2 */ + "m"(C) /* %3 */ + ); +#endif + return (0); +#else + return (-1); +#endif +} + +/*! +\brief Filter using MultByByte: D = saturation255(S * C) + +\param Src1 Pointer to the start of the source byte array (S). +\param Dest Pointer to the start of the destination byte array (D). +\param length The number of bytes in the source arrays. +\param C Constant to multiply with (C). + +\return Returns 0 for success or -1 for error. +*/ +int SDL_imageFilterMultByByte(unsigned char *Src1, unsigned char *Dest, unsigned int length, unsigned char C) +{ + unsigned int i, istart; + int iC; + unsigned char *cursrc1; + unsigned char *curdest; + int result; + + /* Validate input parameters */ + if ((Src1 == NULL) || (Dest == NULL)) + return(-1); + if (length == 0) + return(0); + + /* Special case: C==1 */ + if (C == 1) { + memcpy(Src1, Dest, length); + return (0); + } + + if ((SDL_imageFilterMMXdetect()) && (length > 7)) { + + SDL_imageFilterMultByByteMMX(Src1, Dest, length, C); + + /* Check for unaligned bytes */ + if ((length & 7) > 0) { + /* Setup to process unaligned bytes */ + istart = length & 0xfffffff8; + cursrc1 = &Src1[istart]; + curdest = &Dest[istart]; + } else { + /* No unaligned bytes - we are done */ + return (0); + } + } else { + /* Setup to process whole image */ + istart = 0; + cursrc1 = Src1; + curdest = Dest; + } + + /* C routine to process image */ + iC = (int) C; + for (i = istart; i < length; i++) { + result = (int) *cursrc1 * iC; + if (result > 255) + result = 255; + *curdest = (unsigned char) result; + /* Advance pointers */ + cursrc1++; + curdest++; + } + + return (0); +} + +/*! +\brief Internal MMX Filter using ShiftRightAndMultByByteMMX: D = saturation255((S >> N) * C) + +\param Src1 Pointer to the start of the source byte array (S). +\param Dest Pointer to the start of the destination byte array (D). +\param SrcLength The number of bytes in the source array. +\param N Number of bit-positions to shift (N). Valid range is 0 to 8. +\param C Constant to multiply with (C). + +\return Returns 0 for success or -1 for error. +*/ +int SDL_imageFilterShiftRightAndMultByByteMMX(unsigned char *Src1, unsigned char *Dest, unsigned int SrcLength, unsigned char N, + unsigned char C) +{ +#ifdef USE_MMX +#if !defined(GCC__) + __asm + { + pusha + /* ** Duplicate C in 4 words of MM1 ** */ + mov al, C /* load C into AL */ + xor ah, ah /* zero AH */ + mov bx, ax /* copy AX into BX */ + shl eax, 16 /* shift 2 bytes of EAX left */ + mov ax, bx /* copy BX into AX */ + movd mm1, eax /* copy EAX into MM1 */ + movd mm2, eax /* copy EAX into MM2 */ + punpckldq mm1, mm2 /* fill higher words of MM1 with C */ + xor ecx, ecx /* zero ECX */ + mov cl, N /* load N into CL */ + movd mm7, ecx /* copy N into MM7 */ + pxor mm0, mm0 /* zero MM0 register */ + mov eax, Src1 /* load Src1 address into eax */ + mov edi, Dest /* load Dest address into edi */ + mov ecx, SrcLength /* load loop counter (SIZE) into ecx */ + shr ecx, 3 /* counter/8 (MMX loads 8 bytes at a time) */ + align 16 /* 16 byte alignment of the loop entry */ +L1026: + movq mm3, [eax] /* load 8 bytes from Src1 into MM3 */ + movq mm4, mm3 /* copy MM3 into MM4 */ + punpcklbw mm3, mm0 /* unpack low bytes of SrcDest into words */ + punpckhbw mm4, mm0 /* unpack high bytes of SrcDest into words */ + psrlw mm3, mm7 /* shift 4 WORDS of MM3 (N) bits to the right */ + psrlw mm4, mm7 /* shift 4 WORDS of MM4 (N) bits to the right */ + pmullw mm3, mm1 /* mul low bytes of SrcDest by MM1 */ + pmullw mm4, mm1 /* mul high bytes of SrcDest by MM1 */ + packuswb mm3, mm4 /* pack words back into bytes with saturation */ + movq [edi], mm3 /* store result in Dest */ + add eax, 8 /* increase Src1 register pointer by 8 */ + add edi, 8 /* increase Dest register pointer by 8 */ + dec ecx /* decrease loop counter */ + jnz L1026 /* check loop termination, proceed if required */ + emms /* exit MMX state */ + popa + } +#else + asm volatile + ("pusha \n\t" + /* ** Duplicate C in 4 words of MM1 ** */ + "mov %4, %%al \n\t" /* load C into AL */ + "xor %%ah, %%ah \n\t" /* zero AH */ + "mov %%ax, %%bx \n\t" /* copy AX into BX */ + "shl $16, %%eax \n\t" /* shift 2 bytes of EAX left */ + "mov %%bx, %%ax \n\t" /* copy BX into AX */ + "movd %%eax, %%mm1 \n\t" /* copy EAX into MM1 */ + "movd %%eax, %%mm2 \n\t" /* copy EAX into MM2 */ + "punpckldq %%mm2, %%mm1 \n\t" /* fill higher words of MM1 with C */ + "xor %%ecx, %%ecx \n\t" /* zero ECX */ + "mov %3, %%cl \n\t" /* load N into CL */ + "movd %%ecx, %%mm7 \n\t" /* copy N into MM7 */ + "pxor %%mm0, %%mm0 \n\t" /* zero MM0 register */ + "mov %1, %%eax \n\t" /* load Src1 address into eax */ + "mov %0, %%edi \n\t" /* load Dest address into edi */ + "mov %2, %%ecx \n\t" /* load loop counter (SIZE) into ecx */ + "shr $3, %%ecx \n\t" /* counter/8 (MMX loads 8 bytes at a time) */ + ".align 16 \n\t" /* 16 byte alignment of the loop entry */ + "1: movq (%%eax), %%mm3 \n\t" /* load 8 bytes from Src1 into MM3 */ + "movq %%mm3, %%mm4 \n\t" /* copy MM3 into MM4 */ + "punpcklbw %%mm0, %%mm3 \n\t" /* unpack low bytes of SrcDest into words */ + "punpckhbw %%mm0, %%mm4 \n\t" /* unpack high bytes of SrcDest into words */ + "psrlw %%mm7, %%mm3 \n\t" /* shift 4 WORDS of MM3 (N) bits to the right */ + "psrlw %%mm7, %%mm4 \n\t" /* shift 4 WORDS of MM4 (N) bits to the right */ + "pmullw %%mm1, %%mm3 \n\t" /* mul low bytes of SrcDest by MM1 */ + "pmullw %%mm1, %%mm4 \n\t" /* mul high bytes of SrcDest by MM1 */ + "packuswb %%mm4, %%mm3 \n\t" /* pack words back into bytes with saturation */ + "movq %%mm3, (%%edi) \n\t" /* store result in Dest */ + "add $8, %%eax \n\t" /* increase Src1 register pointer by 8 */ + "add $8, %%edi \n\t" /* increase Dest register pointer by 8 */ + "dec %%ecx \n\t" /* decrease loop counter */ + "jnz 1b \n\t" /* check loop termination, proceed if required */ + "emms \n\t" /* exit MMX state */ + "popa \n\t":"=m" (Dest) /* %0 */ + :"m"(Src1), /* %1 */ + "m"(SrcLength), /* %2 */ + "m"(N), /* %3 */ + "m"(C) /* %4 */ + ); +#endif + return (0); +#else + return (-1); +#endif +} + +/*! +\brief Filter using ShiftRightAndMultByByte: D = saturation255((S >> N) * C) + +\param Src1 Pointer to the start of the source byte array (S). +\param Dest Pointer to the start of the destination byte array (D). +\param length The number of bytes in the source array. +\param N Number of bit-positions to shift (N). Valid range is 0 to 8. +\param C Constant to multiply with (C). + +\return Returns 0 for success or -1 for error. +*/ +int SDL_imageFilterShiftRightAndMultByByte(unsigned char *Src1, unsigned char *Dest, unsigned int length, unsigned char N, + unsigned char C) +{ + unsigned int i, istart; + int iC; + unsigned char *cursrc1; + unsigned char *curdest; + int result; + + /* Validate input parameters */ + if ((Src1 == NULL) || (Dest == NULL)) + return(-1); + if (length == 0) + return(0); + + /* Check shift */ + if (N > 8) { + return (-1); + } + + /* Special case: N==0 && C==1 */ + if ((N == 0) && (C == 1)) { + memcpy(Src1, Dest, length); + return (0); + } + + if ((SDL_imageFilterMMXdetect()) && (length > 7)) { + + SDL_imageFilterShiftRightAndMultByByteMMX(Src1, Dest, length, N, C); + + /* Check for unaligned bytes */ + if ((length & 7) > 0) { + /* Setup to process unaligned bytes */ + istart = length & 0xfffffff8; + cursrc1 = &Src1[istart]; + curdest = &Dest[istart]; + } else { + /* No unaligned bytes - we are done */ + return (0); + } + } else { + /* Setup to process whole image */ + istart = 0; + cursrc1 = Src1; + curdest = Dest; + } + + /* C routine to process image */ + iC = (int) C; + for (i = istart; i < length; i++) { + result = (int) (*cursrc1 >> N) * iC; + if (result > 255) + result = 255; + *curdest = (unsigned char) result; + /* Advance pointers */ + cursrc1++; + curdest++; + } + + return (0); +} + +/*! +\brief Internal MMX Filter using ShiftLeftByte: D = (S << N) + +\param Src1 Pointer to the start of the source byte array (S). +\param Dest Pointer to the start of the destination byte array (D). +\param SrcLength The number of bytes in the source arrays. +\param N Number of bit-positions to shift (N). Valid range is 0 to 8. +\param Mask Byte array containing 8 bytes of 0xFE value. + +\return Returns 0 for success or -1 for error. +*/ +int SDL_imageFilterShiftLeftByteMMX(unsigned char *Src1, unsigned char *Dest, unsigned int SrcLength, unsigned char N, + unsigned char *Mask) +{ +#ifdef USE_MMX +#if !defined(GCC__) + __asm + { + pusha + mov edx, Mask /* load Mask address into edx */ + movq mm0, [edx] /* load Mask into mm0 */ + xor ecx, ecx /* zero ECX */ + mov cl, N /* load loop counter (N) into CL */ + movd mm3, ecx /* copy (N) into MM3 */ + pcmpeqb mm1, mm1 /* generate all 1's in mm1 */ +L10270: /* ** Prepare proper bit-Mask in MM1 ** */ + psllw mm1, 1 /* shift 4 WORDS of MM1 1 bit to the left */ + pand mm1, mm0 // apply Mask to 8 BYTES of MM1 */ + /* byte 0x0f, 0xdb, 0xc8 */ + dec cl /* decrease loop counter */ + jnz L10270 /* check loop termination, proceed if required */ + /* ** Shift all bytes of the image ** */ + mov eax, Src1 /* load Src1 address into eax */ + mov edi, Dest /* load SrcDest address into edi */ + mov ecx, SrcLength /* load loop counter (SIZE) into ecx */ + shr ecx, 3 /* counter/8 (MMX loads 8 bytes at a time) */ + align 16 /* 16 byte alignment of the loop entry */ +L10271: + movq mm0, [eax] /* load 8 bytes from Src1 into MM0 */ + psllw mm0, mm3 /* shift 4 WORDS of MM0 (N) bits to the left */ + pand mm0, mm1 // apply proper bit-Mask to 8 BYTES of MM0 */ + /* byte 0x0f, 0xdb, 0xc1 */ + movq [edi], mm0 /* store result in Dest */ + add eax, 8 /* increase Src1 register pointer by 8 */ + add edi, 8 /* increase Dest register pointer by 8 */ + dec ecx /* decrease loop counter */ + jnz L10271 /* check loop termination, proceed if required */ + emms /* exit MMX state */ + popa + } +#else + asm volatile + ("pusha \n\t" "movl %4, %%edx \n\t" /* load Mask address into edx */ + "movq (%%edx), %%mm0 \n\t" /* load Mask into mm0 */ + "xor %%ecx, %%ecx \n\t" /* zero ECX */ + "mov %3, %%cl \n\t" /* load loop counter (N) into CL */ + "movd %%ecx, %%mm3 \n\t" /* copy (N) into MM3 */ + "pcmpeqb %%mm1, %%mm1 \n\t" /* generate all 1's in mm1 */ + "1: \n\t" /* ** Prepare proper bit-Mask in MM1 ** */ + "psllw $1, %%mm1 \n\t" /* shift 4 WORDS of MM1 1 bit to the left */ + /* "pand %%mm0, %%mm1 \n\t" // apply Mask to 8 BYTES of MM1 */ + ".byte 0x0f, 0xdb, 0xc8 \n\t" "dec %%cl \n\t" /* decrease loop counter */ + "jnz 1b \n\t" /* check loop termination, proceed if required */ + /* ** Shift all bytes of the image ** */ + "mov %1, %%eax \n\t" /* load Src1 address into eax */ + "mov %0, %%edi \n\t" /* load SrcDest address into edi */ + "mov %2, %%ecx \n\t" /* load loop counter (SIZE) into ecx */ + "shr $3, %%ecx \n\t" /* counter/8 (MMX loads 8 bytes at a time) */ + ".align 16 \n\t" /* 16 byte alignment of the loop entry */ + "2: movq (%%eax), %%mm0 \n\t" /* load 8 bytes from Src1 into MM0 */ + "psllw %%mm3, %%mm0 \n\t" /* shift 4 WORDS of MM0 (N) bits to the left */ + /* "pand %%mm1, %%mm0 \n\t" // apply proper bit-Mask to 8 BYTES of MM0 */ + ".byte 0x0f, 0xdb, 0xc1 \n\t" "movq %%mm0, (%%edi) \n\t" /* store result in Dest */ + "add $8, %%eax \n\t" /* increase Src1 register pointer by 8 */ + "add $8, %%edi \n\t" /* increase Dest register pointer by 8 */ + "dec %%ecx \n\t" /* decrease loop counter */ + "jnz 2b \n\t" /* check loop termination, proceed if required */ + "emms \n\t" /* exit MMX state */ + "popa \n\t":"=m" (Dest) /* %0 */ + :"m"(Src1), /* %1 */ + "m"(SrcLength), /* %2 */ + "m"(N), /* %3 */ + "m"(Mask) /* %4 */ + ); +#endif + return (0); +#else + return (-1); +#endif +} + +/*! +\brief Filter using ShiftLeftByte: D = (S << N) + +\param Src1 Pointer to the start of the source byte array (S). +\param Dest Pointer to the start of the destination byte array (D). +\param length The number of bytes in the source arrays. +\param N Number of bit-positions to shift (N). Valid range is 0 to 8. + +\return Returns 0 for success or -1 for error. +*/ +int SDL_imageFilterShiftLeftByte(unsigned char *Src1, unsigned char *Dest, unsigned int length, unsigned char N) +{ + static unsigned char Mask[8] = { 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE }; + unsigned int i, istart; + unsigned char *cursrc1, *curdest; + int result; + + /* Validate input parameters */ + if ((Src1 == NULL) || (Dest == NULL)) + return(-1); + if (length == 0) + return(0); + + if (N > 8) { + return (-1); + } + + /* Special case: N==0 */ + if (N == 0) { + memcpy(Src1, Dest, length); + return (0); + } + + if ((SDL_imageFilterMMXdetect()) && (length > 7)) { + + SDL_imageFilterShiftLeftByteMMX(Src1, Dest, length, N, Mask); + + /* Check for unaligned bytes */ + if ((length & 7) > 0) { + /* Setup to process unaligned bytes */ + istart = length & 0xfffffff8; + cursrc1 = &Src1[istart]; + curdest = &Dest[istart]; + } else { + /* No unaligned bytes - we are done */ + return (0); + } + } else { + /* Setup to process whole image */ + istart = 0; + cursrc1 = Src1; + curdest = Dest; + } + + /* C routine to process image */ + for (i = istart; i < length; i++) { + result = ((int) *cursrc1 << N) & 0xff; + *curdest = (unsigned char) result; + /* Advance pointers */ + cursrc1++; + curdest++; + } + + return (0); +} + +/*! +\brief Internal MMX Filter using ShiftLeftUint: D = ((uint)S << N) + +\param Src1 Pointer to the start of the source byte array (S). +\param Dest Pointer to the start of the destination byte array (D). +\param SrcLength The number of bytes in the source array. +\param N Number of bit-positions to shift (N). Valid range is 0 to 32. + +\return Returns 0 for success or -1 for error. +*/ +int SDL_imageFilterShiftLeftUintMMX(unsigned char *Src1, unsigned char *Dest, unsigned int SrcLength, unsigned char N) +{ +#ifdef USE_MMX +#if !defined(GCC__) + __asm + { + pusha + mov eax, Src1 /* load Src1 address into eax */ + mov edi, Dest /* load Dest address into edi */ + mov ecx, SrcLength /* load loop counter (SIZE) into ecx */ + shr ecx, 3 /* counter/8 (MMX loads 8 bytes at a time) */ + align 16 /* 16 byte alignment of the loop entry */ +L12023: + movq mm0, [eax] /* load 8 bytes from SrcDest into MM0 */ + pslld mm0, N /* MM0=SrcDest+C (add 8 bytes with saturation) */ + movq [edi], mm0 /* store result in SrcDest */ + add eax, 8 /* increase Src1 register pointer by 8 */ + add edi, 8 /* increase Dest register pointer by 8 */ + dec ecx /* decrease loop counter */ + jnz L12023 /* check loop termination, proceed if required */ + emms /* exit MMX state */ + popa + } +#else + asm volatile + ("pusha \n\t" + "mov %1, %%eax \n\t" /* load Src1 address into eax */ + "mov %0, %%edi \n\t" /* load Dest address into edi */ + "mov %2, %%ecx \n\t" /* load loop counter (SIZE) into ecx */ + "shr $3, %%ecx \n\t" /* counter/8 (MMX loads 8 bytes at a time) */ + ".align 16 \n\t" /* 16 byte alignment of the loop entry */ + "1: movq (%%eax), %%mm0 \n\t" /* load 8 bytes from SrcDest into MM0 */ + "pslld %3, %%mm0 \n\t" /* MM0=SrcDest+C (add 8 bytes with saturation) */ + "movq %%mm0, (%%edi) \n\t" /* store result in SrcDest */ + "add $8, %%eax \n\t" /* increase Src1 register pointer by 8 */ + "add $8, %%edi \n\t" /* increase Dest register pointer by 8 */ + "dec %%ecx \n\t" /* decrease loop counter */ + "jnz 1b \n\t" /* check loop termination, proceed if required */ + "emms \n\t" /* exit MMX state */ + "popa \n\t":"=m" (Dest) /* %0 */ + :"m"(Src1), /* %1 */ + "m"(SrcLength), /* %2 */ + "m"(N) /* %3 */ + ); +#endif + return (0); +#else + return (-1); +#endif +} + +/*! +\brief Filter using ShiftLeftUint: D = ((uint)S << N) + +\param Src1 Pointer to the start of the source byte array (S). +\param Dest Pointer to the start of the destination byte array (D). +\param length The number of bytes in the source array. +\param N Number of bit-positions to shift (N). Valid range is 0 to 32. + +\return Returns 0 for success or -1 for error. +*/ +int SDL_imageFilterShiftLeftUint(unsigned char *Src1, unsigned char *Dest, unsigned int length, unsigned char N) +{ + unsigned int i, istart; + unsigned char *cursrc1, *curdest; + unsigned int *icursrc1, *icurdest; + int result; + + /* Validate input parameters */ + if ((Src1 == NULL) || (Dest == NULL)) + return(-1); + if (length == 0) + return(0); + + if (N > 32) { + return (-1); + } + + /* Special case: N==0 */ + if (N == 0) { + memcpy(Src1, Dest, length); + return (0); + } + + if ((SDL_imageFilterMMXdetect()) && (length > 7)) { + + SDL_imageFilterShiftLeftUintMMX(Src1, Dest, length, N); + + /* Check for unaligned bytes */ + if ((length & 7) > 0) { + /* Setup to process unaligned bytes */ + istart = length & 0xfffffff8; + cursrc1 = &Src1[istart]; + curdest = &Dest[istart]; + } else { + /* No unaligned bytes - we are done */ + return (0); + } + } else { + /* Setup to process whole image */ + istart = 0; + cursrc1 = Src1; + curdest = Dest; + } + + /* C routine to process image */ + icursrc1=(unsigned int *)cursrc1; + icurdest=(unsigned int *)curdest; + for (i = istart; i < length; i += 4) { + if ((i+4) 8) { + return (-1); + } + + /* Special case: N==0 */ + if (N == 0) { + memcpy(Src1, Dest, length); + return (0); + } + + if ((SDL_imageFilterMMXdetect()) && (length > 7)) { + + SDL_imageFilterShiftLeftMMX(Src1, Dest, length, N); + + /* Check for unaligned bytes */ + if ((length & 7) > 0) { + /* Setup to process unaligned bytes */ + istart = length & 0xfffffff8; + cursrc1 = &Src1[istart]; + curdest = &Dest[istart]; + } else { + /* No unaligned bytes - we are done */ + return (0); + } + } else { + /* Setup to process whole image */ + istart = 0; + cursrc1 = Src1; + curdest = Dest; + } + + /* C routine to process image */ + for (i = istart; i < length; i++) { + result = (int) *cursrc1 << N; + if (result > 255) + result = 255; + *curdest = (unsigned char) result; + /* Advance pointers */ + cursrc1++; + curdest++; + } + + return (0); +} + +/*! +\brief MMX BinarizeUsingThreshold: D = (S >= T) ? 255:0 + +\param Src1 Pointer to the start of the source byte array (S). +\param Dest Pointer to the start of the destination byte array (D). +\param SrcLength The number of bytes in the source array. +\param T The threshold boundary (inclusive). + +\return Returns 0 for success or -1 for error. +*/ +int SDL_imageFilterBinarizeUsingThresholdMMX(unsigned char *Src1, unsigned char *Dest, unsigned int SrcLength, unsigned char T) +{ +#ifdef USE_MMX +#if !defined(GCC__) + __asm + { + pusha + /* ** Duplicate T in 8 bytes of MM3 ** */ + pcmpeqb mm1, mm1 /* generate all 1's in mm1 */ + pcmpeqb mm2, mm2 /* generate all 1's in mm2 */ + mov al, T /* load T into AL */ + mov ah, al /* copy AL into AH */ + mov bx, ax /* copy AX into BX */ + shl eax, 16 /* shift 2 bytes of EAX left */ + mov ax, bx /* copy BX into AX */ + movd mm3, eax /* copy EAX into MM3 */ + movd mm4, eax /* copy EAX into MM4 */ + punpckldq mm3, mm4 /* fill higher bytes of MM3 with T */ + psubusb mm2, mm3 /* store 0xFF - T in MM2 */ + mov eax, Src1 /* load Src1 address into eax */ + mov edi, Dest /* load Dest address into edi */ + mov ecx, SrcLength /* load loop counter (SIZE) into ecx */ + shr ecx, 3 /* counter/8 (MMX loads 8 bytes at a time) */ + align 16 /* 16 byte alignment of the loop entry */ +L1029: + movq mm0, [eax] /* load 8 bytes from SrcDest into MM0 */ + paddusb mm0, mm2 /* MM0=SrcDest+(0xFF-T) (add 8 bytes with saturation) */ + pcmpeqb mm0, mm1 /* binarize 255:0, comparing to 255 */ + movq [edi], mm0 /* store result in SrcDest */ + add eax, 8 /* increase Src1 register pointer by 8 */ + add edi, 8 /* increase Dest register pointer by 8 */ + dec ecx /* decrease loop counter */ + jnz L1029 /* check loop termination, proceed if required */ + emms /* exit MMX state */ + popa + } +#else + asm volatile + ("pusha \n\t" + /* ** Duplicate T in 8 bytes of MM3 ** */ + "pcmpeqb %%mm1, %%mm1 \n\t" /* generate all 1's in mm1 */ + "pcmpeqb %%mm2, %%mm2 \n\t" /* generate all 1's in mm2 */ + "mov %3, %%al \n\t" /* load T into AL */ + "mov %%al, %%ah \n\t" /* copy AL into AH */ + "mov %%ax, %%bx \n\t" /* copy AX into BX */ + "shl $16, %%eax \n\t" /* shift 2 bytes of EAX left */ + "mov %%bx, %%ax \n\t" /* copy BX into AX */ + "movd %%eax, %%mm3 \n\t" /* copy EAX into MM3 */ + "movd %%eax, %%mm4 \n\t" /* copy EAX into MM4 */ + "punpckldq %%mm4, %%mm3 \n\t" /* fill higher bytes of MM3 with T */ + "psubusb %%mm3, %%mm2 \n\t" /* store 0xFF - T in MM2 */ + "mov %1, %%eax \n\t" /* load Src1 address into eax */ + "mov %0, %%edi \n\t" /* load Dest address into edi */ + "mov %2, %%ecx \n\t" /* load loop counter (SIZE) into ecx */ + "shr $3, %%ecx \n\t" /* counter/8 (MMX loads 8 bytes at a time) */ + ".align 16 \n\t" /* 16 byte alignment of the loop entry */ + "1: \n\t" + "movq (%%eax), %%mm0 \n\t" /* load 8 bytes from SrcDest into MM0 */ + "paddusb %%mm2, %%mm0 \n\t" /* MM0=SrcDest+(0xFF-T) (add 8 bytes with saturation) */ + "pcmpeqb %%mm1, %%mm0 \n\t" /* binarize 255:0, comparing to 255 */ + "movq %%mm0, (%%edi) \n\t" /* store result in SrcDest */ + "add $8, %%eax \n\t" /* increase Src1 register pointer by 8 */ + "add $8, %%edi \n\t" /* increase Dest register pointer by 8 */ + "dec %%ecx \n\t" /* decrease loop counter */ + "jnz 1b \n\t" /* check loop termination, proceed if required */ + "emms \n\t" /* exit MMX state */ + "popa \n\t":"=m" (Dest) /* %0 */ + :"m"(Src1), /* %1 */ + "m"(SrcLength), /* %2 */ + "m"(T) /* %3 */ + ); +#endif + return (0); +#else + return (-1); +#endif +} + +/*! +\brief Filter using BinarizeUsingThreshold: D = (S >= T) ? 255:0 + +\param Src1 Pointer to the start of the source byte array (S). +\param Dest Pointer to the start of the destination byte array (D). +\param length The number of bytes in the source array. +\param T The threshold boundary (inclusive). + +\return Returns 0 for success or -1 for error. +*/ +int SDL_imageFilterBinarizeUsingThreshold(unsigned char *Src1, unsigned char *Dest, unsigned int length, unsigned char T) +{ + unsigned int i, istart; + unsigned char *cursrc1; + unsigned char *curdest; + + /* Validate input parameters */ + if ((Src1 == NULL) || (Dest == NULL)) + return(-1); + if (length == 0) + return(0); + + /* Special case: T==0 */ + if (T == 0) { + memset(Dest, 255, length); + return (0); + } + + if ((SDL_imageFilterMMXdetect()) && (length > 7)) { + + SDL_imageFilterBinarizeUsingThresholdMMX(Src1, Dest, length, T); + + /* Check for unaligned bytes */ + if ((length & 7) > 0) { + /* Setup to process unaligned bytes */ + istart = length & 0xfffffff8; + cursrc1 = &Src1[istart]; + curdest = &Dest[istart]; + } else { + /* No unaligned bytes - we are done */ + return (0); + } + } else { + /* Setup to process whole image */ + istart = 0; + cursrc1 = Src1; + curdest = Dest; + } + + /* C routine to process image */ + for (i = istart; i < length; i++) { + *curdest = ((unsigned char) *cursrc1 >= T) ? 255 : 0; + /* Advance pointers */ + cursrc1++; + curdest++; + } + + return (0); +} + +/*! +\brief Internal MMX Filter using ClipToRange: D = (S >= Tmin) & (S <= Tmax) S:Tmin | Tmax + +\param Src1 Pointer to the start of the source byte array (S). +\param Dest Pointer to the start of the destination byte array (D). +\param SrcLength The number of bytes in the source array. +\param Tmin Lower (inclusive) boundary of the clipping range. +\param Tmax Upper (inclusive) boundary of the clipping range. + +\return Returns 0 for success or -1 for error. +*/ +int SDL_imageFilterClipToRangeMMX(unsigned char *Src1, unsigned char *Dest, unsigned int SrcLength, unsigned char Tmin, + unsigned char Tmax) +{ +#ifdef USE_MMX +#if !defined(GCC__) + __asm + { + pusha + pcmpeqb mm1, mm1 /* generate all 1's in mm1 */ + /* ** Duplicate Tmax in 8 bytes of MM3 ** */ + mov al, Tmax /* load Tmax into AL */ + mov ah, al /* copy AL into AH */ + mov bx, ax /* copy AX into BX */ + shl eax, 16 /* shift 2 bytes of EAX left */ + mov ax, bx /* copy BX into AX */ + movd mm3, eax /* copy EAX into MM3 */ + movd mm4, eax /* copy EAX into MM4 */ + punpckldq mm3, mm4 /* fill higher bytes of MM3 with Tmax */ + psubusb mm1, mm3 /* store 0xFF - Tmax in MM1 */ + /* ** Duplicate Tmin in 8 bytes of MM5 ** */ + mov al, Tmin /* load Tmin into AL */ + mov ah, al /* copy AL into AH */ + mov bx, ax /* copy AX into BX */ + shl eax, 16 /* shift 2 bytes of EAX left */ + mov ax, bx /* copy BX into AX */ + movd mm5, eax /* copy EAX into MM5 */ + movd mm4, eax /* copy EAX into MM4 */ + punpckldq mm5, mm4 /* fill higher bytes of MM5 with Tmin */ + movq mm7, mm5 /* copy MM5 into MM7 */ + paddusb mm7, mm1 /* store 0xFF - Tmax + Tmin in MM7 */ + mov eax, Src1 /* load Src1 address into eax */ + mov edi, Dest /* load Dest address into edi */ + mov ecx, SrcLength /* load loop counter (SIZE) into ecx */ + shr ecx, 3 /* counter/8 (MMX loads 8 bytes at a time) */ + align 16 /* 16 byte alignment of the loop entry */ +L1030: + movq mm0, [eax] /* load 8 bytes from Src1 into MM0 */ + paddusb mm0, mm1 /* MM0=SrcDest+(0xFF-Tmax) */ + psubusb mm0, mm7 /* MM0=MM0-(0xFF-Tmax+Tmin) */ + paddusb mm0, mm5 /* MM0=MM0+Tmin */ + movq [edi], mm0 /* store result in Dest */ + add eax, 8 /* increase Src1 register pointer by 8 */ + add edi, 8 /* increase Dest register pointer by 8 */ + dec ecx /* decrease loop counter */ + jnz L1030 /* check loop termination, proceed if required */ + emms /* exit MMX state */ + popa + } +#else + asm volatile + ("pusha \n\t" "pcmpeqb %%mm1, %%mm1 \n\t" /* generate all 1's in mm1 */ + /* ** Duplicate Tmax in 8 bytes of MM3 ** */ + "mov %4, %%al \n\t" /* load Tmax into AL */ + "mov %%al, %%ah \n\t" /* copy AL into AH */ + "mov %%ax, %%bx \n\t" /* copy AX into BX */ + "shl $16, %%eax \n\t" /* shift 2 bytes of EAX left */ + "mov %%bx, %%ax \n\t" /* copy BX into AX */ + "movd %%eax, %%mm3 \n\t" /* copy EAX into MM3 */ + "movd %%eax, %%mm4 \n\t" /* copy EAX into MM4 */ + "punpckldq %%mm4, %%mm3 \n\t" /* fill higher bytes of MM3 with Tmax */ + "psubusb %%mm3, %%mm1 \n\t" /* store 0xFF - Tmax in MM1 */ + /* ** Duplicate Tmin in 8 bytes of MM5 ** */ + "mov %3, %%al \n\t" /* load Tmin into AL */ + "mov %%al, %%ah \n\t" /* copy AL into AH */ + "mov %%ax, %%bx \n\t" /* copy AX into BX */ + "shl $16, %%eax \n\t" /* shift 2 bytes of EAX left */ + "mov %%bx, %%ax \n\t" /* copy BX into AX */ + "movd %%eax, %%mm5 \n\t" /* copy EAX into MM5 */ + "movd %%eax, %%mm4 \n\t" /* copy EAX into MM4 */ + "punpckldq %%mm4, %%mm5 \n\t" /* fill higher bytes of MM5 with Tmin */ + "movq %%mm5, %%mm7 \n\t" /* copy MM5 into MM7 */ + "paddusb %%mm1, %%mm7 \n\t" /* store 0xFF - Tmax + Tmin in MM7 */ + "mov %1, %%eax \n\t" /* load Src1 address into eax */ + "mov %0, %%edi \n\t" /* load Dest address into edi */ + "mov %2, %%ecx \n\t" /* load loop counter (SIZE) into ecx */ + "shr $3, %%ecx \n\t" /* counter/8 (MMX loads 8 bytes at a time) */ + ".align 16 \n\t" /* 16 byte alignment of the loop entry */ + "1: \n\t" + "movq (%%eax), %%mm0 \n\t" /* load 8 bytes from Src1 into MM0 */ + "paddusb %%mm1, %%mm0 \n\t" /* MM0=SrcDest+(0xFF-Tmax) */ + "psubusb %%mm7, %%mm0 \n\t" /* MM0=MM0-(0xFF-Tmax+Tmin) */ + "paddusb %%mm5, %%mm0 \n\t" /* MM0=MM0+Tmin */ + "movq %%mm0, (%%edi) \n\t" /* store result in Dest */ + "add $8, %%eax \n\t" /* increase Src1 register pointer by 8 */ + "add $8, %%edi \n\t" /* increase Dest register pointer by 8 */ + "dec %%ecx \n\t" /* decrease loop counter */ + "jnz 1b \n\t" /* check loop termination, proceed if required */ + "emms \n\t" /* exit MMX state */ + "popa \n\t":"=m" (Dest) /* %0 */ + :"m"(Src1), /* %1 */ + "m"(SrcLength), /* %2 */ + "m"(Tmin), /* %3 */ + "m"(Tmax) /* %4 */ + ); +#endif + return (0); +#else + return (-1); +#endif +} + +/*! +\brief Filter using ClipToRange: D = (S >= Tmin) & (S <= Tmax) S:Tmin | Tmax + +\param Src1 Pointer to the start of the source byte array (S). +\param Dest Pointer to the start of the destination byte array (D). +\param length The number of bytes in the source array. +\param Tmin Lower (inclusive) boundary of the clipping range. +\param Tmax Upper (inclusive) boundary of the clipping range. + +\return Returns 0 for success or -1 for error. +*/ +int SDL_imageFilterClipToRange(unsigned char *Src1, unsigned char *Dest, unsigned int length, unsigned char Tmin, + unsigned char Tmax) +{ + unsigned int i, istart; + unsigned char *cursrc1; + unsigned char *curdest; + + /* Validate input parameters */ + if ((Src1 == NULL) || (Dest == NULL)) + return(-1); + if (length == 0) + return(0); + + /* Special case: Tmin==0 && Tmax = 255 */ + if ((Tmin == 0) && (Tmax == 25)) { + memcpy(Src1, Dest, length); + return (0); + } + + if ((SDL_imageFilterMMXdetect()) && (length > 7)) { + + SDL_imageFilterClipToRangeMMX(Src1, Dest, length, Tmin, Tmax); + + /* Check for unaligned bytes */ + if ((length & 7) > 0) { + /* Setup to process unaligned bytes */ + istart = length & 0xfffffff8; + cursrc1 = &Src1[istart]; + curdest = &Dest[istart]; + } else { + /* No unaligned bytes - we are done */ + return (0); + } + } else { + /* Setup to process whole image */ + istart = 0; + cursrc1 = Src1; + curdest = Dest; + } + + /* C routine to process image */ + for (i = istart; i < length; i++) { + if (*cursrc1 < Tmin) { + *curdest = Tmin; + } else if (*cursrc1 > Tmax) { + *curdest = Tmax; + } else { + *curdest = *cursrc1; + } + /* Advance pointers */ + cursrc1++; + curdest++; + } + + return (0); +} + +/*! +\brief Internal MMX Filter using NormalizeLinear: D = saturation255((Nmax - Nmin)/(Cmax - Cmin)*(S - Cmin) + Nmin) + +\param Src1 Pointer to the start of the source byte array (S). +\param Dest Pointer to the start of the destination byte array (D). +\param SrcLength The number of bytes in the source array. +\param Cmin Normalization constant (Cmin). +\param Cmax Normalization constant (Cmax). +\param Nmin Normalization constant (Nmin). +\param Nmax Normalization constant (Nmax). + +\return Returns 0 for success or -1 for error. +*/ +int SDL_imageFilterNormalizeLinearMMX(unsigned char *Src1, unsigned char *Dest, unsigned int SrcLength, int Cmin, int Cmax, + int Nmin, int Nmax) +{ +#ifdef USE_MMX +#if !defined(GCC__) + __asm + { + pusha + mov ax, WORD PTR Nmax /* load Nmax in AX */ + mov bx, WORD PTR Cmax /* load Cmax in BX */ + sub ax, WORD PTR Nmin /* AX = Nmax - Nmin */ + sub bx, WORD PTR Cmin /* BX = Cmax - Cmin */ + jz L10311 /* check division by zero */ + xor dx, dx /* prepare for division, zero DX */ + div bx /* AX = AX/BX */ + jmp L10312 +L10311: + mov ax, 255 /* if div by zero, assume result max byte value */ +L10312: /* ** Duplicate AX in 4 words of MM0 ** */ + mov bx, ax /* copy AX into BX */ + shl eax, 16 /* shift 2 bytes of EAX left */ + mov ax, bx /* copy BX into AX */ + movd mm0, eax /* copy EAX into MM0 */ + movd mm1, eax /* copy EAX into MM1 */ + punpckldq mm0, mm1 /* fill higher words of MM0 with AX */ + /* ** Duplicate Cmin in 4 words of MM1 ** */ + mov ax, WORD PTR Cmin /* load Cmin into AX */ + mov bx, ax /* copy AX into BX */ + shl eax, 16 /* shift 2 bytes of EAX left */ + mov ax, bx /* copy BX into AX */ + movd mm1, eax /* copy EAX into MM1 */ + movd mm2, eax /* copy EAX into MM2 */ + punpckldq mm1, mm2 /* fill higher words of MM1 with Cmin */ + /* ** Duplicate Nmin in 4 words of MM2 ** */ + mov ax, WORD PTR Nmin /* load Nmin into AX */ + mov bx, ax /* copy AX into BX */ + shl eax, 16 /* shift 2 bytes of EAX left */ + mov ax, bx /* copy BX into AX */ + movd mm2, eax /* copy EAX into MM2 */ + movd mm3, eax /* copy EAX into MM3 */ + punpckldq mm2, mm3 /* fill higher words of MM2 with Nmin */ + pxor mm7, mm7 /* zero MM7 register */ + mov eax, Src1 /* load Src1 address into eax */ + mov edi, Dest /* load Dest address into edi */ + mov ecx, SrcLength /* load loop counter (SIZE) into ecx */ + shr ecx, 3 /* counter/8 (MMX loads 8 bytes at a time) */ + align 16 /* 16 byte alignment of the loop entry */ +L1031: + movq mm3, [eax] /* load 8 bytes from Src1 into MM3 */ + movq mm4, mm3 /* copy MM3 into MM4 */ + punpcklbw mm3, mm7 /* unpack low bytes of SrcDest into words */ + punpckhbw mm4, mm7 /* unpack high bytes of SrcDest into words */ + psubusb mm3, mm1 /* S-Cmin, low bytes */ + psubusb mm4, mm1 /* S-Cmin, high bytes */ + pmullw mm3, mm0 /* MM0*(S-Cmin), low bytes */ + pmullw mm4, mm0 /* MM0*(S-Cmin), high bytes */ + paddusb mm3, mm2 /* MM0*(S-Cmin)+Nmin, low bytes */ + paddusb mm4, mm2 /* MM0*(S-Cmin)+Nmin, high bytes */ + /* ** Take abs value of the signed words ** */ + movq mm5, mm3 /* copy mm3 into mm5 */ + movq mm6, mm4 /* copy mm4 into mm6 */ + psraw mm5, 15 /* fill mm5 words with word sign bit */ + psraw mm6, 15 /* fill mm6 words with word sign bit */ + pxor mm3, mm5 /* take 1's compliment of only neg words */ + pxor mm4, mm6 /* take 1's compliment of only neg words */ + psubsw mm3, mm5 /* add 1 to only neg words, W-(-1) or W-0 */ + psubsw mm4, mm6 /* add 1 to only neg words, W-(-1) or W-0 */ + packuswb mm3, mm4 /* pack words back into bytes with saturation */ + movq [edi], mm3 /* store result in Dest */ + add eax, 8 /* increase Src1 register pointer by 8 */ + add edi, 8 /* increase Dest register pointer by 8 */ + dec ecx /* decrease loop counter */ + jnz L1031 /* check loop termination, proceed if required */ + emms /* exit MMX state */ + popa + } +#else + asm volatile + ("pusha \n\t" "mov %6, %%ax \n\t" /* load Nmax in AX */ + "mov %4, %%bx \n\t" /* load Cmax in BX */ + "sub %5, %%ax \n\t" /* AX = Nmax - Nmin */ + "sub %3, %%bx \n\t" /* BX = Cmax - Cmin */ + "jz 1f \n\t" /* check division by zero */ + "xor %%dx, %%dx \n\t" /* prepare for division, zero DX */ + "div %%bx \n\t" /* AX = AX/BX */ + "jmp 2f \n\t" "1: \n\t" "mov $255, %%ax \n\t" /* if div by zero, assume result max. byte value */ + "2: \n\t" /* ** Duplicate AX in 4 words of MM0 ** */ + "mov %%ax, %%bx \n\t" /* copy AX into BX */ + "shl $16, %%eax \n\t" /* shift 2 bytes of EAX left */ + "mov %%bx, %%ax \n\t" /* copy BX into AX */ + "movd %%eax, %%mm0 \n\t" /* copy EAX into MM0 */ + "movd %%eax, %%mm1 \n\t" /* copy EAX into MM1 */ + "punpckldq %%mm1, %%mm0 \n\t" /* fill higher words of MM0 with AX */ + /* ** Duplicate Cmin in 4 words of MM1 ** */ + "mov %3, %%ax \n\t" /* load Cmin into AX */ + "mov %%ax, %%bx \n\t" /* copy AX into BX */ + "shl $16, %%eax \n\t" /* shift 2 bytes of EAX left */ + "mov %%bx, %%ax \n\t" /* copy BX into AX */ + "movd %%eax, %%mm1 \n\t" /* copy EAX into MM1 */ + "movd %%eax, %%mm2 \n\t" /* copy EAX into MM2 */ + "punpckldq %%mm2, %%mm1 \n\t" /* fill higher words of MM1 with Cmin */ + /* ** Duplicate Nmin in 4 words of MM2 ** */ + "mov %5, %%ax \n\t" /* load Nmin into AX */ + "mov %%ax, %%bx \n\t" /* copy AX into BX */ + "shl $16, %%eax \n\t" /* shift 2 bytes of EAX left */ + "mov %%bx, %%ax \n\t" /* copy BX into AX */ + "movd %%eax, %%mm2 \n\t" /* copy EAX into MM2 */ + "movd %%eax, %%mm3 \n\t" /* copy EAX into MM3 */ + "punpckldq %%mm3, %%mm2 \n\t" /* fill higher words of MM2 with Nmin */ + "pxor %%mm7, %%mm7 \n\t" /* zero MM7 register */ + "mov %1, %%eax \n\t" /* load Src1 address into eax */ + "mov %0, %%edi \n\t" /* load Dest address into edi */ + "mov %2, %%ecx \n\t" /* load loop counter (SIZE) into ecx */ + "shr $3, %%ecx \n\t" /* counter/8 (MMX loads 8 bytes at a time) */ + ".align 16 \n\t" /* 16 byte alignment of the loop entry */ + "1: \n\t" + "movq (%%eax), %%mm3 \n\t" /* load 8 bytes from Src1 into MM3 */ + "movq %%mm3, %%mm4 \n\t" /* copy MM3 into MM4 */ + "punpcklbw %%mm7, %%mm3 \n\t" /* unpack low bytes of SrcDest into words */ + "punpckhbw %%mm7, %%mm4 \n\t" /* unpack high bytes of SrcDest into words */ + "psubusb %%mm1, %%mm3 \n\t" /* S-Cmin, low bytes */ + "psubusb %%mm1, %%mm4 \n\t" /* S-Cmin, high bytes */ + "pmullw %%mm0, %%mm3 \n\t" /* MM0*(S-Cmin), low bytes */ + "pmullw %%mm0, %%mm4 \n\t" /* MM0*(S-Cmin), high bytes */ + "paddusb %%mm2, %%mm3 \n\t" /* MM0*(S-Cmin)+Nmin, low bytes */ + "paddusb %%mm2, %%mm4 \n\t" /* MM0*(S-Cmin)+Nmin, high bytes */ + /* ** Take abs value of the signed words ** */ + "movq %%mm3, %%mm5 \n\t" /* copy mm3 into mm5 */ + "movq %%mm4, %%mm6 \n\t" /* copy mm4 into mm6 */ + "psraw $15, %%mm5 \n\t" /* fill mm5 words with word sign bit */ + "psraw $15, %%mm6 \n\t" /* fill mm6 words with word sign bit */ + "pxor %%mm5, %%mm3 \n\t" /* take 1's compliment of only neg. words */ + "pxor %%mm6, %%mm4 \n\t" /* take 1's compliment of only neg. words */ + "psubsw %%mm5, %%mm3 \n\t" /* add 1 to only neg. words, W-(-1) or W-0 */ + "psubsw %%mm6, %%mm4 \n\t" /* add 1 to only neg. words, W-(-1) or W-0 */ + "packuswb %%mm4, %%mm3 \n\t" /* pack words back into bytes with saturation */ + "movq %%mm3, (%%edi) \n\t" /* store result in Dest */ + "add $8, %%eax \n\t" /* increase Src1 register pointer by 8 */ + "add $8, %%edi \n\t" /* increase Dest register pointer by 8 */ + "dec %%ecx \n\t" /* decrease loop counter */ + "jnz 1b \n\t" /* check loop termination, proceed if required */ + "emms \n\t" /* exit MMX state */ + "popa \n\t":"=m" (Dest) /* %0 */ + :"m"(Src1), /* %1 */ + "m"(SrcLength), /* %2 */ + "m"(Cmin), /* %3 */ + "m"(Cmax), /* %4 */ + "m"(Nmin), /* %5 */ + "m"(Nmax) /* %6 */ + ); +#endif + return (0); +#else + return (-1); +#endif +} + +/*! +\brief Filter using NormalizeLinear: D = saturation255((Nmax - Nmin)/(Cmax - Cmin)*(S - Cmin) + Nmin) + +\param Src Pointer to the start of the source byte array (S). +\param Dest Pointer to the start of the destination byte array (D). +\param length The number of bytes in the source array. +\param Cmin Normalization constant. +\param Cmax Normalization constant. +\param Nmin Normalization constant. +\param Nmax Normalization constant. + +\return Returns 0 for success or -1 for error. +*/ +int SDL_imageFilterNormalizeLinear(unsigned char *Src, unsigned char *Dest, unsigned int length, int Cmin, int Cmax, int Nmin, + int Nmax) +{ + unsigned int i, istart; + unsigned char *cursrc; + unsigned char *curdest; + int dN, dC, factor; + int result; + + /* Validate input parameters */ + if ((Src == NULL) || (Dest == NULL)) + return(-1); + if (length == 0) + return(0); + + if ((SDL_imageFilterMMXdetect()) && (length > 7)) { + + SDL_imageFilterNormalizeLinearMMX(Src, Dest, length, Cmin, Cmax, Nmin, Nmax); + + /* Check for unaligned bytes */ + if ((length & 7) > 0) { + /* Setup to process unaligned bytes */ + istart = length & 0xfffffff8; + cursrc = &Src[istart]; + curdest = &Dest[istart]; + } else { + /* No unaligned bytes - we are done */ + return (0); + } + } else { + /* Setup to process whole image */ + istart = 0; + cursrc = Src; + curdest = Dest; + } + + /* C routine to process image */ + dC = Cmax - Cmin; + if (dC == 0) + return (0); + dN = Nmax - Nmin; + factor = dN / dC; + for (i = istart; i < length; i++) { + result = factor * ((int) (*cursrc) - Cmin) + Nmin; + if (result > 255) + result = 255; + *curdest = (unsigned char) result; + /* Advance pointers */ + cursrc++; + curdest++; + } + + return (0); +} + +/* ------------------------------------------------------------------------------------ */ + +/*! +\brief Filter using ConvolveKernel3x3Divide: Dij = saturation0and255( ... ) + +\param Src The source 2D byte array to convolve. Should be different from destination. +\param Dest The destination 2D byte array to store the result in. Should be different from source. +\param rows Number of rows in source/destination array. Must be >2. +\param columns Number of columns in source/destination array. Must be >2. +\param Kernel The 2D convolution kernel of size 3x3. +\param Divisor The divisor of the convolution sum. Must be >0. + +Note: Non-MMX implementation not available for this function. + +\return Returns 1 if filter was applied, 0 otherwise. +*/ +int SDL_imageFilterConvolveKernel3x3Divide(unsigned char *Src, unsigned char *Dest, int rows, int columns, + signed short *Kernel, unsigned char Divisor) +{ + /* Validate input parameters */ + if ((Src == NULL) || (Dest == NULL) || (Kernel == NULL)) + return(-1); + + if ((columns < 3) || (rows < 3) || (Divisor == 0)) + return (-1); + + if ((SDL_imageFilterMMXdetect())) { +#ifdef USE_MMX +#if !defined(GCC__) + __asm + { + pusha + pxor mm0, mm0 /* zero MM0 */ + xor ebx, ebx /* zero EBX */ + mov bl, Divisor /* load Divisor into BL */ + mov edx, Kernel /* load Kernel address into EDX */ + movq mm5, [edx] /* MM5 = {0,K2,K1,K0} */ + add edx, 8 /* second row |K0 K1 K2 0| */ + movq mm6, [edx] /* MM6 = {0,K5,K4,K3} K = |K3 K4 K5 0| */ + add edx, 8 /* third row |K6 K7 K8 0| */ + movq mm7, [edx] /* MM7 = {0,K8,K7,K6} */ + /* ---, */ + mov eax, columns /* load columns into EAX */ + mov esi, Src /* ESI = Src row 0 address */ + mov edi, Dest /* load Dest address to EDI */ + add edi, eax /* EDI = EDI + columns */ + inc edi /* 1 byte offset from the left edge */ + mov edx, rows /* initialize ROWS counter */ + sub edx, 2 /* do not use first and last row */ + /* ---, */ +L10320: + mov ecx, eax /* initialize COLUMS counter */ + sub ecx, 2 /* do not use first and last column */ + align 16 /* 16 byte alignment of the loop entry */ +L10322: + /* ---, */ + movq mm1, [esi] /* load 8 bytes of the image first row */ + add esi, eax /* move one row below */ + movq mm2, [esi] /* load 8 bytes of the image second row */ + add esi, eax /* move one row below */ + movq mm3, [esi] /* load 8 bytes of the image third row */ + punpcklbw mm1, mm0 /* unpack first 4 bytes into words */ + punpcklbw mm2, mm0 /* unpack first 4 bytes into words */ + punpcklbw mm3, mm0 /* unpack first 4 bytes into words */ + pmullw mm1, mm5 /* multiply words first row image*Kernel */ + pmullw mm2, mm6 /* multiply words second row image*Kernel */ + pmullw mm3, mm7 /* multiply words third row image*Kernel */ + paddsw mm1, mm2 /* add 4 words of the first and second rows */ + paddsw mm1, mm3 /* add 4 words of the third row and result */ + movq mm2, mm1 /* copy MM1 into MM2 */ + psrlq mm1, 32 /* shift 2 left words to the right */ + paddsw mm1, mm2 /* add 2 left and 2 right result words */ + movq mm3, mm1 /* copy MM1 into MM3 */ + psrlq mm1, 16 /* shift 1 left word to the right */ + paddsw mm1, mm3 /* add 1 left and 1 right result words */ + /* --, */ + movd mm2, eax /* save EAX in MM2 */ + movd mm3, edx /* save EDX in MM3 */ + movd eax, mm1 /* copy MM1 into EAX */ + psraw mm1, 15 /* spread sign bit of the result */ + movd edx, mm1 /* fill EDX with a sign bit */ + idiv bx /* IDIV - VERY EXPENSIVE */ + movd mm1, eax /* move result of division into MM1 */ + packuswb mm1, mm0 /* pack division result with saturation */ + movd eax, mm1 /* copy saturated result into EAX */ + mov [edi], al /* copy a byte result into Dest */ + movd edx, mm3 /* restore saved EDX */ + movd eax, mm2 /* restore saved EAX */ + /* --, */ + sub esi, eax /* move two rows up */ + sub esi, eax /* */ + inc esi /* move Src pointer to the next pixel */ + inc edi /* move Dest pointer to the next pixel */ + /* ---, */ + dec ecx /* decrease loop counter COLUMNS */ + jnz L10322 /* check loop termination, proceed if required */ + add esi, 2 /* move to the next row in Src */ + add edi, 2 /* move to the next row in Dest */ + dec edx /* decrease loop counter ROWS */ + jnz L10320 /* check loop termination, proceed if required */ + /* ---, */ + emms /* exit MMX state */ + popa + } +#else + asm volatile + ("pusha \n\t" "pxor %%mm0, %%mm0 \n\t" /* zero MM0 */ + "xor %%ebx, %%ebx \n\t" /* zero EBX */ + "mov %5, %%bl \n\t" /* load Divisor into BL */ + "mov %4, %%edx \n\t" /* load Kernel address into EDX */ + "movq (%%edx), %%mm5 \n\t" /* MM5 = {0,K2,K1,K0} */ + "add $8, %%edx \n\t" /* second row |K0 K1 K2 0| */ + "movq (%%edx), %%mm6 \n\t" /* MM6 = {0,K5,K4,K3} K = |K3 K4 K5 0| */ + "add $8, %%edx \n\t" /* third row |K6 K7 K8 0| */ + "movq (%%edx), %%mm7 \n\t" /* MM7 = {0,K8,K7,K6} */ + /* --- */ + "mov %3, %%eax \n\t" /* load columns into EAX */ + "mov %1, %%esi \n\t" /* ESI = Src row 0 address */ + "mov %0, %%edi \n\t" /* load Dest address to EDI */ + "add %%eax, %%edi \n\t" /* EDI = EDI + columns */ + "inc %%edi \n\t" /* 1 byte offset from the left edge */ + "mov %2, %%edx \n\t" /* initialize ROWS counter */ + "sub $2, %%edx \n\t" /* do not use first and last row */ + /* --- */ + ".L10320: \n\t" "mov %%eax, %%ecx \n\t" /* initialize COLUMS counter */ + "sub $2, %%ecx \n\t" /* do not use first and last column */ + ".align 16 \n\t" /* 16 byte alignment of the loop entry */ + ".L10322: \n\t" + /* --- */ + "movq (%%esi), %%mm1 \n\t" /* load 8 bytes of the image first row */ + "add %%eax, %%esi \n\t" /* move one row below */ + "movq (%%esi), %%mm2 \n\t" /* load 8 bytes of the image second row */ + "add %%eax, %%esi \n\t" /* move one row below */ + "movq (%%esi), %%mm3 \n\t" /* load 8 bytes of the image third row */ + "punpcklbw %%mm0, %%mm1 \n\t" /* unpack first 4 bytes into words */ + "punpcklbw %%mm0, %%mm2 \n\t" /* unpack first 4 bytes into words */ + "punpcklbw %%mm0, %%mm3 \n\t" /* unpack first 4 bytes into words */ + "pmullw %%mm5, %%mm1 \n\t" /* multiply words first row image*Kernel */ + "pmullw %%mm6, %%mm2 \n\t" /* multiply words second row image*Kernel */ + "pmullw %%mm7, %%mm3 \n\t" /* multiply words third row image*Kernel */ + "paddsw %%mm2, %%mm1 \n\t" /* add 4 words of the first and second rows */ + "paddsw %%mm3, %%mm1 \n\t" /* add 4 words of the third row and result */ + "movq %%mm1, %%mm2 \n\t" /* copy MM1 into MM2 */ + "psrlq $32, %%mm1 \n\t" /* shift 2 left words to the right */ + "paddsw %%mm2, %%mm1 \n\t" /* add 2 left and 2 right result words */ + "movq %%mm1, %%mm3 \n\t" /* copy MM1 into MM3 */ + "psrlq $16, %%mm1 \n\t" /* shift 1 left word to the right */ + "paddsw %%mm3, %%mm1 \n\t" /* add 1 left and 1 right result words */ + /* -- */ + "movd %%eax, %%mm2 \n\t" /* save EAX in MM2 */ + "movd %%edx, %%mm3 \n\t" /* save EDX in MM3 */ + "movd %%mm1, %%eax \n\t" /* copy MM1 into EAX */ + "psraw $15, %%mm1 \n\t" /* spread sign bit of the result */ + "movd %%mm1, %%edx \n\t" /* fill EDX with a sign bit */ + "idivw %%bx \n\t" /* IDIV - VERY EXPENSIVE */ + "movd %%eax, %%mm1 \n\t" /* move result of division into MM1 */ + "packuswb %%mm0, %%mm1 \n\t" /* pack division result with saturation */ + "movd %%mm1, %%eax \n\t" /* copy saturated result into EAX */ + "mov %%al, (%%edi) \n\t" /* copy a byte result into Dest */ + "movd %%mm3, %%edx \n\t" /* restore saved EDX */ + "movd %%mm2, %%eax \n\t" /* restore saved EAX */ + /* -- */ + "sub %%eax, %%esi \n\t" /* move two rows up */ + "sub %%eax, %%esi \n\t" /* */ + "inc %%esi \n\t" /* move Src pointer to the next pixel */ + "inc %%edi \n\t" /* move Dest pointer to the next pixel */ + /* --- */ + "dec %%ecx \n\t" /* decrease loop counter COLUMNS */ + "jnz .L10322 \n\t" /* check loop termination, proceed if required */ + "add $2, %%esi \n\t" /* move to the next row in Src */ + "add $2, %%edi \n\t" /* move to the next row in Dest */ + "dec %%edx \n\t" /* decrease loop counter ROWS */ + "jnz .L10320 \n\t" /* check loop termination, proceed if required */ + /* --- */ + "emms \n\t" /* exit MMX state */ + "popa \n\t":"=m" (Dest) /* %0 */ + :"m"(Src), /* %1 */ + "m"(rows), /* %2 */ + "m"(columns), /* %3 */ + "m"(Kernel), /* %4 */ + "m"(Divisor) /* %5 */ + ); +#endif +#endif + return (0); + } else { + /* No non-MMX implementation yet */ + return (-1); + } +} + +/*! +\brief Filter using ConvolveKernel5x5Divide: Dij = saturation0and255( ... ) + +\param Src The source 2D byte array to convolve. Should be different from destination. +\param Dest The destination 2D byte array to store the result in. Should be different from source. +\param rows Number of rows in source/destination array. Must be >4. +\param columns Number of columns in source/destination array. Must be >4. +\param Kernel The 2D convolution kernel of size 5x5. +\param Divisor The divisor of the convolution sum. Must be >0. + +Note: Non-MMX implementation not available for this function. + +\return Returns 1 if filter was applied, 0 otherwise. +*/ +int SDL_imageFilterConvolveKernel5x5Divide(unsigned char *Src, unsigned char *Dest, int rows, int columns, + signed short *Kernel, unsigned char Divisor) +{ + /* Validate input parameters */ + if ((Src == NULL) || (Dest == NULL) || (Kernel == NULL)) + return(-1); + + if ((columns < 5) || (rows < 5) || (Divisor == 0)) + return (-1); + + if ((SDL_imageFilterMMXdetect())) { +#ifdef USE_MMX +#if !defined(GCC__) + __asm + { + pusha + pxor mm0, mm0 /* zero MM0 */ + xor ebx, ebx /* zero EBX */ + mov bl, Divisor /* load Divisor into BL */ + movd mm5, ebx /* copy Divisor into MM5 */ + mov edx, Kernel /* load Kernel address into EDX */ + mov esi, Src /* load Src address to ESI */ + mov edi, Dest /* load Dest address to EDI */ + add edi, 2 /* 2 column offset from the left edge */ + mov eax, columns /* load columns into EAX */ + shl eax, 1 /* EAX = columns * 2 */ + add edi, eax /* 2 row offset from the top edge */ + shr eax, 1 /* EAX = columns */ + mov ebx, rows /* initialize ROWS counter */ + sub ebx, 4 /* do not use first 2 and last 2 rows */ + /* ---, */ +L10330: + mov ecx, eax /* initialize COLUMNS counter */ + sub ecx, 4 /* do not use first 2 and last 2 columns */ + align 16 /* 16 byte alignment of the loop entry */ +L10332: + pxor mm7, mm7 /* zero MM7 (accumulator) */ + movd mm6, esi /* save ESI in MM6 */ + /* --- 1 */ + movq mm1, [esi] /* load 8 bytes of the Src */ + movq mm2, mm1 /* copy MM1 into MM2 */ + add esi, eax /* move Src pointer 1 row below */ + movq mm3, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + movq mm4, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + punpcklbw mm1, mm0 /* unpack first 4 bytes into words */ + punpckhbw mm2, mm0 /* unpack second 4 bytes into words */ + pmullw mm1, mm3 /* mult 4 low words of Src and Kernel */ + pmullw mm2, mm4 /* mult 4 high words of Src and Kernel */ + paddsw mm1, mm2 /* add 4 words of the high and low bytes */ + paddsw mm7, mm1 /* add MM1 to accumulator MM7 */ + /* --- 2 */ + movq mm1, [esi] /* load 8 bytes of the Src */ + movq mm2, mm1 /* copy MM1 into MM2 */ + add esi, eax /* move Src pointer 1 row below */ + movq mm3, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + movq mm4, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + punpcklbw mm1, mm0 /* unpack first 4 bytes into words */ + punpckhbw mm2, mm0 /* unpack second 4 bytes into words */ + pmullw mm1, mm3 /* mult 4 low words of Src and Kernel */ + pmullw mm2, mm4 /* mult 4 high words of Src and Kernel */ + paddsw mm1, mm2 /* add 4 words of the high and low bytes */ + paddsw mm7, mm1 /* add MM1 to accumulator MM7 */ + /* --- 3 */ + movq mm1, [esi] /* load 8 bytes of the Src */ + movq mm2, mm1 /* copy MM1 into MM2 */ + add esi, eax /* move Src pointer 1 row below */ + movq mm3, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + movq mm4, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + punpcklbw mm1, mm0 /* unpack first 4 bytes into words */ + punpckhbw mm2, mm0 /* unpack second 4 bytes into words */ + pmullw mm1, mm3 /* mult 4 low words of Src and Kernel */ + pmullw mm2, mm4 /* mult 4 high words of Src and Kernel */ + paddsw mm1, mm2 /* add 4 words of the high and low bytes */ + paddsw mm7, mm1 /* add MM1 to accumulator MM7 */ + /* --- 4 */ + movq mm1, [esi] /* load 8 bytes of the Src */ + movq mm2, mm1 /* copy MM1 into MM2 */ + add esi, eax /* move Src pointer 1 row below */ + movq mm3, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + movq mm4, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + punpcklbw mm1, mm0 /* unpack first 4 bytes into words */ + punpckhbw mm2, mm0 /* unpack second 4 bytes into words */ + pmullw mm1, mm3 /* mult 4 low words of Src and Kernel */ + pmullw mm2, mm4 /* mult 4 high words of Src and Kernel */ + paddsw mm1, mm2 /* add 4 words of the high and low bytes */ + paddsw mm7, mm1 /* add MM1 to accumulator MM7 */ + /* --- 5 */ + movq mm1, [esi] /* load 8 bytes of the Src */ + movq mm2, mm1 /* copy MM1 into MM2 */ + movq mm3, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + movq mm4, [edx] /* load 4 words of Kernel */ + punpcklbw mm1, mm0 /* unpack first 4 bytes into words */ + punpckhbw mm2, mm0 /* unpack second 4 bytes into words */ + pmullw mm1, mm3 /* mult 4 low words of Src and Kernel */ + pmullw mm2, mm4 /* mult 4 high words of Src and Kernel */ + paddsw mm1, mm2 /* add 4 words of the high and low bytes */ + paddsw mm7, mm1 /* add MM1 to accumulator MM7 */ + /* ---, */ + movq mm3, mm7 /* copy MM7 into MM3 */ + psrlq mm7, 32 /* shift 2 left words to the right */ + paddsw mm7, mm3 /* add 2 left and 2 right result words */ + movq mm2, mm7 /* copy MM7 into MM2 */ + psrlq mm7, 16 /* shift 1 left word to the right */ + paddsw mm7, mm2 /* add 1 left and 1 right result words */ + /* ---, */ + movd mm1, eax /* save EDX in MM1 */ + movd mm2, ebx /* save EDX in MM2 */ + movd mm3, edx /* save EDX in MM3 */ + movd eax, mm7 /* load summation result into EAX */ + psraw mm7, 15 /* spread sign bit of the result */ + movd ebx, mm5 /* load Divisor into EBX */ + movd edx, mm7 /* fill EDX with a sign bit */ + idiv bx /* IDIV - VERY EXPENSIVE */ + movd mm7, eax /* move result of division into MM7 */ + packuswb mm7, mm0 /* pack division result with saturation */ + movd eax, mm7 /* copy saturated result into EAX */ + mov [edi], al /* copy a byte result into Dest */ + movd edx, mm3 /* restore saved EDX */ + movd ebx, mm2 /* restore saved EBX */ + movd eax, mm1 /* restore saved EAX */ + /* --, */ + movd esi, mm6 /* move Src pointer to the top pixel */ + sub edx, 72 /* EDX = Kernel address */ + inc esi /* move Src pointer to the next pixel */ + inc edi /* move Dest pointer to the next pixel */ + /* ---, */ + dec ecx /* decrease loop counter COLUMNS */ + jnz L10332 /* check loop termination, proceed if required */ + add esi, 4 /* move to the next row in Src */ + add edi, 4 /* move to the next row in Dest */ + dec ebx /* decrease loop counter ROWS */ + jnz L10330 /* check loop termination, proceed if required */ + /* ---, */ + emms /* exit MMX state */ + popa + } +#else + asm volatile + ("pusha \n\t" "pxor %%mm0, %%mm0 \n\t" /* zero MM0 */ + "xor %%ebx, %%ebx \n\t" /* zero EBX */ + "mov %5, %%bl \n\t" /* load Divisor into BL */ + "movd %%ebx, %%mm5 \n\t" /* copy Divisor into MM5 */ + "mov %4, %%edx \n\t" /* load Kernel address into EDX */ + "mov %1, %%esi \n\t" /* load Src address to ESI */ + "mov %0, %%edi \n\t" /* load Dest address to EDI */ + "add $2, %%edi \n\t" /* 2 column offset from the left edge */ + "mov %3, %%eax \n\t" /* load columns into EAX */ + "shl $1, %%eax \n\t" /* EAX = columns * 2 */ + "add %%eax, %%edi \n\t" /* 2 row offset from the top edge */ + "shr $1, %%eax \n\t" /* EAX = columns */ + "mov %2, %%ebx \n\t" /* initialize ROWS counter */ + "sub $4, %%ebx \n\t" /* do not use first 2 and last 2 rows */ + /* --- */ + ".L10330: \n\t" "mov %%eax, %%ecx \n\t" /* initialize COLUMNS counter */ + "sub $4, %%ecx \n\t" /* do not use first 2 and last 2 columns */ + ".align 16 \n\t" /* 16 byte alignment of the loop entry */ + ".L10332: \n\t" "pxor %%mm7, %%mm7 \n\t" /* zero MM7 (accumulator) */ + "movd %%esi, %%mm6 \n\t" /* save ESI in MM6 */ + /* --- 1 */ + "movq (%%esi), %%mm1 \n\t" /* load 8 bytes of the Src */ + "movq %%mm1, %%mm2 \n\t" /* copy MM1 into MM2 */ + "add %%eax, %%esi \n\t" /* move Src pointer 1 row below */ + "movq (%%edx), %%mm3 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "movq (%%edx), %%mm4 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "punpcklbw %%mm0, %%mm1 \n\t" /* unpack first 4 bytes into words */ + "punpckhbw %%mm0, %%mm2 \n\t" /* unpack second 4 bytes into words */ + "pmullw %%mm3, %%mm1 \n\t" /* mult. 4 low words of Src and Kernel */ + "pmullw %%mm4, %%mm2 \n\t" /* mult. 4 high words of Src and Kernel */ + "paddsw %%mm2, %%mm1 \n\t" /* add 4 words of the high and low bytes */ + "paddsw %%mm1, %%mm7 \n\t" /* add MM1 to accumulator MM7 */ + /* --- 2 */ + "movq (%%esi), %%mm1 \n\t" /* load 8 bytes of the Src */ + "movq %%mm1, %%mm2 \n\t" /* copy MM1 into MM2 */ + "add %%eax, %%esi \n\t" /* move Src pointer 1 row below */ + "movq (%%edx), %%mm3 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "movq (%%edx), %%mm4 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "punpcklbw %%mm0, %%mm1 \n\t" /* unpack first 4 bytes into words */ + "punpckhbw %%mm0, %%mm2 \n\t" /* unpack second 4 bytes into words */ + "pmullw %%mm3, %%mm1 \n\t" /* mult. 4 low words of Src and Kernel */ + "pmullw %%mm4, %%mm2 \n\t" /* mult. 4 high words of Src and Kernel */ + "paddsw %%mm2, %%mm1 \n\t" /* add 4 words of the high and low bytes */ + "paddsw %%mm1, %%mm7 \n\t" /* add MM1 to accumulator MM7 */ + /* --- 3 */ + "movq (%%esi), %%mm1 \n\t" /* load 8 bytes of the Src */ + "movq %%mm1, %%mm2 \n\t" /* copy MM1 into MM2 */ + "add %%eax, %%esi \n\t" /* move Src pointer 1 row below */ + "movq (%%edx), %%mm3 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "movq (%%edx), %%mm4 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "punpcklbw %%mm0, %%mm1 \n\t" /* unpack first 4 bytes into words */ + "punpckhbw %%mm0, %%mm2 \n\t" /* unpack second 4 bytes into words */ + "pmullw %%mm3, %%mm1 \n\t" /* mult. 4 low words of Src and Kernel */ + "pmullw %%mm4, %%mm2 \n\t" /* mult. 4 high words of Src and Kernel */ + "paddsw %%mm2, %%mm1 \n\t" /* add 4 words of the high and low bytes */ + "paddsw %%mm1, %%mm7 \n\t" /* add MM1 to accumulator MM7 */ + /* --- 4 */ + "movq (%%esi), %%mm1 \n\t" /* load 8 bytes of the Src */ + "movq %%mm1, %%mm2 \n\t" /* copy MM1 into MM2 */ + "add %%eax, %%esi \n\t" /* move Src pointer 1 row below */ + "movq (%%edx), %%mm3 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "movq (%%edx), %%mm4 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "punpcklbw %%mm0, %%mm1 \n\t" /* unpack first 4 bytes into words */ + "punpckhbw %%mm0, %%mm2 \n\t" /* unpack second 4 bytes into words */ + "pmullw %%mm3, %%mm1 \n\t" /* mult. 4 low words of Src and Kernel */ + "pmullw %%mm4, %%mm2 \n\t" /* mult. 4 high words of Src and Kernel */ + "paddsw %%mm2, %%mm1 \n\t" /* add 4 words of the high and low bytes */ + "paddsw %%mm1, %%mm7 \n\t" /* add MM1 to accumulator MM7 */ + /* --- 5 */ + "movq (%%esi), %%mm1 \n\t" /* load 8 bytes of the Src */ + "movq %%mm1, %%mm2 \n\t" /* copy MM1 into MM2 */ + "movq (%%edx), %%mm3 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "movq (%%edx), %%mm4 \n\t" /* load 4 words of Kernel */ + "punpcklbw %%mm0, %%mm1 \n\t" /* unpack first 4 bytes into words */ + "punpckhbw %%mm0, %%mm2 \n\t" /* unpack second 4 bytes into words */ + "pmullw %%mm3, %%mm1 \n\t" /* mult. 4 low words of Src and Kernel */ + "pmullw %%mm4, %%mm2 \n\t" /* mult. 4 high words of Src and Kernel */ + "paddsw %%mm2, %%mm1 \n\t" /* add 4 words of the high and low bytes */ + "paddsw %%mm1, %%mm7 \n\t" /* add MM1 to accumulator MM7 */ + /* --- */ + "movq %%mm7, %%mm3 \n\t" /* copy MM7 into MM3 */ + "psrlq $32, %%mm7 \n\t" /* shift 2 left words to the right */ + "paddsw %%mm3, %%mm7 \n\t" /* add 2 left and 2 right result words */ + "movq %%mm7, %%mm2 \n\t" /* copy MM7 into MM2 */ + "psrlq $16, %%mm7 \n\t" /* shift 1 left word to the right */ + "paddsw %%mm2, %%mm7 \n\t" /* add 1 left and 1 right result words */ + /* --- */ + "movd %%eax, %%mm1 \n\t" /* save EDX in MM1 */ + "movd %%ebx, %%mm2 \n\t" /* save EDX in MM2 */ + "movd %%edx, %%mm3 \n\t" /* save EDX in MM3 */ + "movd %%mm7, %%eax \n\t" /* load summation result into EAX */ + "psraw $15, %%mm7 \n\t" /* spread sign bit of the result */ + "movd %%mm5, %%ebx \n\t" /* load Divisor into EBX */ + "movd %%mm7, %%edx \n\t" /* fill EDX with a sign bit */ + "idivw %%bx \n\t" /* IDIV - VERY EXPENSIVE */ + "movd %%eax, %%mm7 \n\t" /* move result of division into MM7 */ + "packuswb %%mm0, %%mm7 \n\t" /* pack division result with saturation */ + "movd %%mm7, %%eax \n\t" /* copy saturated result into EAX */ + "mov %%al, (%%edi) \n\t" /* copy a byte result into Dest */ + "movd %%mm3, %%edx \n\t" /* restore saved EDX */ + "movd %%mm2, %%ebx \n\t" /* restore saved EBX */ + "movd %%mm1, %%eax \n\t" /* restore saved EAX */ + /* -- */ + "movd %%mm6, %%esi \n\t" /* move Src pointer to the top pixel */ + "sub $72, %%edx \n\t" /* EDX = Kernel address */ + "inc %%esi \n\t" /* move Src pointer to the next pixel */ + "inc %%edi \n\t" /* move Dest pointer to the next pixel */ + /* --- */ + "dec %%ecx \n\t" /* decrease loop counter COLUMNS */ + "jnz .L10332 \n\t" /* check loop termination, proceed if required */ + "add $4, %%esi \n\t" /* move to the next row in Src */ + "add $4, %%edi \n\t" /* move to the next row in Dest */ + "dec %%ebx \n\t" /* decrease loop counter ROWS */ + "jnz .L10330 \n\t" /* check loop termination, proceed if required */ + /* --- */ + "emms \n\t" /* exit MMX state */ + "popa \n\t":"=m" (Dest) /* %0 */ + :"m"(Src), /* %1 */ + "m"(rows), /* %2 */ + "m"(columns), /* %3 */ + "m"(Kernel), /* %4 */ + "m"(Divisor) /* %5 */ + ); +#endif +#endif + return (0); + } else { + /* No non-MMX implementation yet */ + return (-1); + } +} + +/*! +\brief Filter using ConvolveKernel7x7Divide: Dij = saturation0and255( ... ) + +\param Src The source 2D byte array to convolve. Should be different from destination. +\param Dest The destination 2D byte array to store the result in. Should be different from source. +\param rows Number of rows in source/destination array. Must be >6. +\param columns Number of columns in source/destination array. Must be >6. +\param Kernel The 2D convolution kernel of size 7x7. +\param Divisor The divisor of the convolution sum. Must be >0. + +Note: Non-MMX implementation not available for this function. + +\return Returns 1 if filter was applied, 0 otherwise. +*/ +int SDL_imageFilterConvolveKernel7x7Divide(unsigned char *Src, unsigned char *Dest, int rows, int columns, + signed short *Kernel, unsigned char Divisor) +{ + /* Validate input parameters */ + if ((Src == NULL) || (Dest == NULL) || (Kernel == NULL)) + return(-1); + + if ((columns < 7) || (rows < 7) || (Divisor == 0)) + return (-1); + + if ((SDL_imageFilterMMXdetect())) { +#ifdef USE_MMX +#if !defined(GCC__) + __asm + { + pusha + pxor mm0, mm0 /* zero MM0 */ + xor ebx, ebx /* zero EBX */ + mov bl, Divisor /* load Divisor into BL */ + movd mm5, ebx /* copy Divisor into MM5 */ + mov edx, Kernel /* load Kernel address into EDX */ + mov esi, Src /* load Src address to ESI */ + mov edi, Dest /* load Dest address to EDI */ + add edi, 3 /* 3 column offset from the left edge */ + mov eax, columns /* load columns into EAX */ + add edi, eax /* 3 row offset from the top edge */ + add edi, eax + add edi, eax + mov ebx, rows /* initialize ROWS counter */ + sub ebx, 6 /* do not use first 3 and last 3 rows */ + /* ---, */ +L10340: + mov ecx, eax /* initialize COLUMNS counter */ + sub ecx, 6 /* do not use first 3 and last 3 columns */ + align 16 /* 16 byte alignment of the loop entry */ +L10342: + pxor mm7, mm7 /* zero MM7 (accumulator) */ + movd mm6, esi /* save ESI in MM6 */ + /* --- 1 */ + movq mm1, [esi] /* load 8 bytes of the Src */ + movq mm2, mm1 /* copy MM1 into MM2 */ + add esi, eax /* move Src pointer 1 row below */ + movq mm3, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + movq mm4, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + punpcklbw mm1, mm0 /* unpack first 4 bytes into words */ + punpckhbw mm2, mm0 /* unpack second 4 bytes into words */ + pmullw mm1, mm3 /* mult 4 low words of Src and Kernel */ + pmullw mm2, mm4 /* mult 4 high words of Src and Kernel */ + paddsw mm1, mm2 /* add 4 words of the high and low bytes */ + paddsw mm7, mm1 /* add MM1 to accumulator MM7 */ + /* --- 2 */ + movq mm1, [esi] /* load 8 bytes of the Src */ + movq mm2, mm1 /* copy MM1 into MM2 */ + add esi, eax /* move Src pointer 1 row below */ + movq mm3, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + movq mm4, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + punpcklbw mm1, mm0 /* unpack first 4 bytes into words */ + punpckhbw mm2, mm0 /* unpack second 4 bytes into words */ + pmullw mm1, mm3 /* mult 4 low words of Src and Kernel */ + pmullw mm2, mm4 /* mult 4 high words of Src and Kernel */ + paddsw mm1, mm2 /* add 4 words of the high and low bytes */ + paddsw mm7, mm1 /* add MM1 to accumulator MM7 */ + /* --- 3 */ + movq mm1, [esi] /* load 8 bytes of the Src */ + movq mm2, mm1 /* copy MM1 into MM2 */ + add esi, eax /* move Src pointer 1 row below */ + movq mm3, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + movq mm4, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + punpcklbw mm1, mm0 /* unpack first 4 bytes into words */ + punpckhbw mm2, mm0 /* unpack second 4 bytes into words */ + pmullw mm1, mm3 /* mult 4 low words of Src and Kernel */ + pmullw mm2, mm4 /* mult 4 high words of Src and Kernel */ + paddsw mm1, mm2 /* add 4 words of the high and low bytes */ + paddsw mm7, mm1 /* add MM1 to accumulator MM7 */ + /* --- 4 */ + movq mm1, [esi] /* load 8 bytes of the Src */ + movq mm2, mm1 /* copy MM1 into MM2 */ + add esi, eax /* move Src pointer 1 row below */ + movq mm3, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + movq mm4, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + punpcklbw mm1, mm0 /* unpack first 4 bytes into words */ + punpckhbw mm2, mm0 /* unpack second 4 bytes into words */ + pmullw mm1, mm3 /* mult 4 low words of Src and Kernel */ + pmullw mm2, mm4 /* mult 4 high words of Src and Kernel */ + paddsw mm1, mm2 /* add 4 words of the high and low bytes */ + paddsw mm7, mm1 /* add MM1 to accumulator MM7 */ + /* --- 5 */ + movq mm1, [esi] /* load 8 bytes of the Src */ + movq mm2, mm1 /* copy MM1 into MM2 */ + add esi, eax /* move Src pointer 1 row below */ + movq mm3, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + movq mm4, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + punpcklbw mm1, mm0 /* unpack first 4 bytes into words */ + punpckhbw mm2, mm0 /* unpack second 4 bytes into words */ + pmullw mm1, mm3 /* mult 4 low words of Src and Kernel */ + pmullw mm2, mm4 /* mult 4 high words of Src and Kernel */ + paddsw mm1, mm2 /* add 4 words of the high and low bytes */ + paddsw mm7, mm1 /* add MM1 to accumulator MM7 */ + /* --- 6 */ + movq mm1, [esi] /* load 8 bytes of the Src */ + movq mm2, mm1 /* copy MM1 into MM2 */ + add esi, eax /* move Src pointer 1 row below */ + movq mm3, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + movq mm4, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + punpcklbw mm1, mm0 /* unpack first 4 bytes into words */ + punpckhbw mm2, mm0 /* unpack second 4 bytes into words */ + pmullw mm1, mm3 /* mult 4 low words of Src and Kernel */ + pmullw mm2, mm4 /* mult 4 high words of Src and Kernel */ + paddsw mm1, mm2 /* add 4 words of the high and low bytes */ + paddsw mm7, mm1 /* add MM1 to accumulator MM7 */ + /* --- 7 */ + movq mm1, [esi] /* load 8 bytes of the Src */ + movq mm2, mm1 /* copy MM1 into MM2 */ + movq mm3, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + movq mm4, [edx] /* load 4 words of Kernel */ + punpcklbw mm1, mm0 /* unpack first 4 bytes into words */ + punpckhbw mm2, mm0 /* unpack second 4 bytes into words */ + pmullw mm1, mm3 /* mult 4 low words of Src and Kernel */ + pmullw mm2, mm4 /* mult 4 high words of Src and Kernel */ + paddsw mm1, mm2 /* add 4 words of the high and low bytes */ + paddsw mm7, mm1 /* add MM1 to accumulator MM7 */ + /* ---, */ + movq mm3, mm7 /* copy MM7 into MM3 */ + psrlq mm7, 32 /* shift 2 left words to the right */ + paddsw mm7, mm3 /* add 2 left and 2 right result words */ + movq mm2, mm7 /* copy MM7 into MM2 */ + psrlq mm7, 16 /* shift 1 left word to the right */ + paddsw mm7, mm2 /* add 1 left and 1 right result words */ + /* ---, */ + movd mm1, eax /* save EDX in MM1 */ + movd mm2, ebx /* save EDX in MM2 */ + movd mm3, edx /* save EDX in MM3 */ + movd eax, mm7 /* load summation result into EAX */ + psraw mm7, 15 /* spread sign bit of the result */ + movd ebx, mm5 /* load Divisor into EBX */ + movd edx, mm7 /* fill EDX with a sign bit */ + idiv bx /* IDIV - VERY EXPENSIVE */ + movd mm7, eax /* move result of division into MM7 */ + packuswb mm7, mm0 /* pack division result with saturation */ + movd eax, mm7 /* copy saturated result into EAX */ + mov [edi], al /* copy a byte result into Dest */ + movd edx, mm3 /* restore saved EDX */ + movd ebx, mm2 /* restore saved EBX */ + movd eax, mm1 /* restore saved EAX */ + /* --, */ + movd esi, mm6 /* move Src pointer to the top pixel */ + sub edx, 104 /* EDX = Kernel address */ + inc esi /* move Src pointer to the next pixel */ + inc edi /* move Dest pointer to the next pixel */ + /* ---, */ + dec ecx /* decrease loop counter COLUMNS */ + jnz L10342 /* check loop termination, proceed if required */ + add esi, 6 /* move to the next row in Src */ + add edi, 6 /* move to the next row in Dest */ + dec ebx /* decrease loop counter ROWS */ + jnz L10340 /* check loop termination, proceed if required */ + /* ---, */ + emms /* exit MMX state */ + popa + } +#else + asm volatile + ("pusha \n\t" "pxor %%mm0, %%mm0 \n\t" /* zero MM0 */ + "xor %%ebx, %%ebx \n\t" /* zero EBX */ + "mov %5, %%bl \n\t" /* load Divisor into BL */ + "movd %%ebx, %%mm5 \n\t" /* copy Divisor into MM5 */ + "mov %4, %%edx \n\t" /* load Kernel address into EDX */ + "mov %1, %%esi \n\t" /* load Src address to ESI */ + "mov %0, %%edi \n\t" /* load Dest address to EDI */ + "add $3, %%edi \n\t" /* 3 column offset from the left edge */ + "mov %3, %%eax \n\t" /* load columns into EAX */ + "add %%eax, %%edi \n\t" /* 3 row offset from the top edge */ + "add %%eax, %%edi \n\t" "add %%eax, %%edi \n\t" "mov %2, %%ebx \n\t" /* initialize ROWS counter */ + "sub $6, %%ebx \n\t" /* do not use first 3 and last 3 rows */ + /* --- */ + ".L10340: \n\t" "mov %%eax, %%ecx \n\t" /* initialize COLUMNS counter */ + "sub $6, %%ecx \n\t" /* do not use first 3 and last 3 columns */ + ".align 16 \n\t" /* 16 byte alignment of the loop entry */ + ".L10342: \n\t" "pxor %%mm7, %%mm7 \n\t" /* zero MM7 (accumulator) */ + "movd %%esi, %%mm6 \n\t" /* save ESI in MM6 */ + /* --- 1 */ + "movq (%%esi), %%mm1 \n\t" /* load 8 bytes of the Src */ + "movq %%mm1, %%mm2 \n\t" /* copy MM1 into MM2 */ + "add %%eax, %%esi \n\t" /* move Src pointer 1 row below */ + "movq (%%edx), %%mm3 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "movq (%%edx), %%mm4 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "punpcklbw %%mm0, %%mm1 \n\t" /* unpack first 4 bytes into words */ + "punpckhbw %%mm0, %%mm2 \n\t" /* unpack second 4 bytes into words */ + "pmullw %%mm3, %%mm1 \n\t" /* mult. 4 low words of Src and Kernel */ + "pmullw %%mm4, %%mm2 \n\t" /* mult. 4 high words of Src and Kernel */ + "paddsw %%mm2, %%mm1 \n\t" /* add 4 words of the high and low bytes */ + "paddsw %%mm1, %%mm7 \n\t" /* add MM1 to accumulator MM7 */ + /* --- 2 */ + "movq (%%esi), %%mm1 \n\t" /* load 8 bytes of the Src */ + "movq %%mm1, %%mm2 \n\t" /* copy MM1 into MM2 */ + "add %%eax, %%esi \n\t" /* move Src pointer 1 row below */ + "movq (%%edx), %%mm3 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "movq (%%edx), %%mm4 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "punpcklbw %%mm0, %%mm1 \n\t" /* unpack first 4 bytes into words */ + "punpckhbw %%mm0, %%mm2 \n\t" /* unpack second 4 bytes into words */ + "pmullw %%mm3, %%mm1 \n\t" /* mult. 4 low words of Src and Kernel */ + "pmullw %%mm4, %%mm2 \n\t" /* mult. 4 high words of Src and Kernel */ + "paddsw %%mm2, %%mm1 \n\t" /* add 4 words of the high and low bytes */ + "paddsw %%mm1, %%mm7 \n\t" /* add MM1 to accumulator MM7 */ + /* --- 3 */ + "movq (%%esi), %%mm1 \n\t" /* load 8 bytes of the Src */ + "movq %%mm1, %%mm2 \n\t" /* copy MM1 into MM2 */ + "add %%eax, %%esi \n\t" /* move Src pointer 1 row below */ + "movq (%%edx), %%mm3 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "movq (%%edx), %%mm4 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "punpcklbw %%mm0, %%mm1 \n\t" /* unpack first 4 bytes into words */ + "punpckhbw %%mm0, %%mm2 \n\t" /* unpack second 4 bytes into words */ + "pmullw %%mm3, %%mm1 \n\t" /* mult. 4 low words of Src and Kernel */ + "pmullw %%mm4, %%mm2 \n\t" /* mult. 4 high words of Src and Kernel */ + "paddsw %%mm2, %%mm1 \n\t" /* add 4 words of the high and low bytes */ + "paddsw %%mm1, %%mm7 \n\t" /* add MM1 to accumulator MM7 */ + /* --- 4 */ + "movq (%%esi), %%mm1 \n\t" /* load 8 bytes of the Src */ + "movq %%mm1, %%mm2 \n\t" /* copy MM1 into MM2 */ + "add %%eax, %%esi \n\t" /* move Src pointer 1 row below */ + "movq (%%edx), %%mm3 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "movq (%%edx), %%mm4 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "punpcklbw %%mm0, %%mm1 \n\t" /* unpack first 4 bytes into words */ + "punpckhbw %%mm0, %%mm2 \n\t" /* unpack second 4 bytes into words */ + "pmullw %%mm3, %%mm1 \n\t" /* mult. 4 low words of Src and Kernel */ + "pmullw %%mm4, %%mm2 \n\t" /* mult. 4 high words of Src and Kernel */ + "paddsw %%mm2, %%mm1 \n\t" /* add 4 words of the high and low bytes */ + "paddsw %%mm1, %%mm7 \n\t" /* add MM1 to accumulator MM7 */ + /* --- 5 */ + "movq (%%esi), %%mm1 \n\t" /* load 8 bytes of the Src */ + "movq %%mm1, %%mm2 \n\t" /* copy MM1 into MM2 */ + "add %%eax, %%esi \n\t" /* move Src pointer 1 row below */ + "movq (%%edx), %%mm3 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "movq (%%edx), %%mm4 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "punpcklbw %%mm0, %%mm1 \n\t" /* unpack first 4 bytes into words */ + "punpckhbw %%mm0, %%mm2 \n\t" /* unpack second 4 bytes into words */ + "pmullw %%mm3, %%mm1 \n\t" /* mult. 4 low words of Src and Kernel */ + "pmullw %%mm4, %%mm2 \n\t" /* mult. 4 high words of Src and Kernel */ + "paddsw %%mm2, %%mm1 \n\t" /* add 4 words of the high and low bytes */ + "paddsw %%mm1, %%mm7 \n\t" /* add MM1 to accumulator MM7 */ + /* --- 6 */ + "movq (%%esi), %%mm1 \n\t" /* load 8 bytes of the Src */ + "movq %%mm1, %%mm2 \n\t" /* copy MM1 into MM2 */ + "add %%eax, %%esi \n\t" /* move Src pointer 1 row below */ + "movq (%%edx), %%mm3 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "movq (%%edx), %%mm4 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "punpcklbw %%mm0, %%mm1 \n\t" /* unpack first 4 bytes into words */ + "punpckhbw %%mm0, %%mm2 \n\t" /* unpack second 4 bytes into words */ + "pmullw %%mm3, %%mm1 \n\t" /* mult. 4 low words of Src and Kernel */ + "pmullw %%mm4, %%mm2 \n\t" /* mult. 4 high words of Src and Kernel */ + "paddsw %%mm2, %%mm1 \n\t" /* add 4 words of the high and low bytes */ + "paddsw %%mm1, %%mm7 \n\t" /* add MM1 to accumulator MM7 */ + /* --- 7 */ + "movq (%%esi), %%mm1 \n\t" /* load 8 bytes of the Src */ + "movq %%mm1, %%mm2 \n\t" /* copy MM1 into MM2 */ + "movq (%%edx), %%mm3 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "movq (%%edx), %%mm4 \n\t" /* load 4 words of Kernel */ + "punpcklbw %%mm0, %%mm1 \n\t" /* unpack first 4 bytes into words */ + "punpckhbw %%mm0, %%mm2 \n\t" /* unpack second 4 bytes into words */ + "pmullw %%mm3, %%mm1 \n\t" /* mult. 4 low words of Src and Kernel */ + "pmullw %%mm4, %%mm2 \n\t" /* mult. 4 high words of Src and Kernel */ + "paddsw %%mm2, %%mm1 \n\t" /* add 4 words of the high and low bytes */ + "paddsw %%mm1, %%mm7 \n\t" /* add MM1 to accumulator MM7 */ + /* --- */ + "movq %%mm7, %%mm3 \n\t" /* copy MM7 into MM3 */ + "psrlq $32, %%mm7 \n\t" /* shift 2 left words to the right */ + "paddsw %%mm3, %%mm7 \n\t" /* add 2 left and 2 right result words */ + "movq %%mm7, %%mm2 \n\t" /* copy MM7 into MM2 */ + "psrlq $16, %%mm7 \n\t" /* shift 1 left word to the right */ + "paddsw %%mm2, %%mm7 \n\t" /* add 1 left and 1 right result words */ + /* --- */ + "movd %%eax, %%mm1 \n\t" /* save EDX in MM1 */ + "movd %%ebx, %%mm2 \n\t" /* save EDX in MM2 */ + "movd %%edx, %%mm3 \n\t" /* save EDX in MM3 */ + "movd %%mm7, %%eax \n\t" /* load summation result into EAX */ + "psraw $15, %%mm7 \n\t" /* spread sign bit of the result */ + "movd %%mm5, %%ebx \n\t" /* load Divisor into EBX */ + "movd %%mm7, %%edx \n\t" /* fill EDX with a sign bit */ + "idivw %%bx \n\t" /* IDIV - VERY EXPENSIVE */ + "movd %%eax, %%mm7 \n\t" /* move result of division into MM7 */ + "packuswb %%mm0, %%mm7 \n\t" /* pack division result with saturation */ + "movd %%mm7, %%eax \n\t" /* copy saturated result into EAX */ + "mov %%al, (%%edi) \n\t" /* copy a byte result into Dest */ + "movd %%mm3, %%edx \n\t" /* restore saved EDX */ + "movd %%mm2, %%ebx \n\t" /* restore saved EBX */ + "movd %%mm1, %%eax \n\t" /* restore saved EAX */ + /* -- */ + "movd %%mm6, %%esi \n\t" /* move Src pointer to the top pixel */ + "sub $104, %%edx \n\t" /* EDX = Kernel address */ + "inc %%esi \n\t" /* move Src pointer to the next pixel */ + "inc %%edi \n\t" /* move Dest pointer to the next pixel */ + /* --- */ + "dec %%ecx \n\t" /* decrease loop counter COLUMNS */ + "jnz .L10342 \n\t" /* check loop termination, proceed if required */ + "add $6, %%esi \n\t" /* move to the next row in Src */ + "add $6, %%edi \n\t" /* move to the next row in Dest */ + "dec %%ebx \n\t" /* decrease loop counter ROWS */ + "jnz .L10340 \n\t" /* check loop termination, proceed if required */ + /* --- */ + "emms \n\t" /* exit MMX state */ + "popa \n\t":"=m" (Dest) /* %0 */ + :"m"(Src), /* %1 */ + "m"(rows), /* %2 */ + "m"(columns), /* %3 */ + "m"(Kernel), /* %4 */ + "m"(Divisor) /* %5 */ + ); +#endif +#endif + return (0); + } else { + /* No non-MMX implementation yet */ + return (-1); + } +} + +/*! +\brief Filter using ConvolveKernel9x9Divide: Dij = saturation0and255( ... ) + +\param Src The source 2D byte array to convolve. Should be different from destination. +\param Dest The destination 2D byte array to store the result in. Should be different from source. +\param rows Number of rows in source/destination array. Must be >8. +\param columns Number of columns in source/destination array. Must be >8. +\param Kernel The 2D convolution kernel of size 9x9. +\param Divisor The divisor of the convolution sum. Must be >0. + +Note: Non-MMX implementation not available for this function. + +\return Returns 1 if filter was applied, 0 otherwise. +*/ +int SDL_imageFilterConvolveKernel9x9Divide(unsigned char *Src, unsigned char *Dest, int rows, int columns, + signed short *Kernel, unsigned char Divisor) +{ + /* Validate input parameters */ + if ((Src == NULL) || (Dest == NULL) || (Kernel == NULL)) + return(-1); + + if ((columns < 9) || (rows < 9) || (Divisor == 0)) + return (-1); + + if ((SDL_imageFilterMMXdetect())) { +#ifdef USE_MMX +#if !defined(GCC__) + __asm + { + pusha + pxor mm0, mm0 /* zero MM0 */ + xor ebx, ebx /* zero EBX */ + mov bl, Divisor /* load Divisor into BL */ + movd mm5, ebx /* copy Divisor into MM5 */ + mov edx, Kernel /* load Kernel address into EDX */ + mov esi, Src /* load Src address to ESI */ + mov edi, Dest /* load Dest address to EDI */ + add edi, 4 /* 4 column offset from the left edge */ + mov eax, columns /* load columns into EAX */ + add edi, eax /* 4 row offset from the top edge */ + add edi, eax + add edi, eax + add edi, eax + mov ebx, rows /* initialize ROWS counter */ + sub ebx, 8 /* do not use first 4 and last 4 rows */ + /* ---, */ +L10350: + mov ecx, eax /* initialize COLUMNS counter */ + sub ecx, 8 /* do not use first 4 and last 4 columns */ + align 16 /* 16 byte alignment of the loop entry */ +L10352: + pxor mm7, mm7 /* zero MM7 (accumulator) */ + movd mm6, esi /* save ESI in MM6 */ + /* --- 1 */ + movq mm1, [esi] /* load 8 bytes of the Src */ + movq mm2, mm1 /* copy MM1 into MM2 */ + inc esi /* move pointer to the next 8 bytes of Src */ + movq mm3, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + movq mm4, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + punpcklbw mm1, mm0 /* unpack first 4 bytes into words */ + punpckhbw mm2, mm0 /* unpack second 4 bytes into words */ + pmullw mm1, mm3 /* mult. 4 low words of Src and Kernel */ + pmullw mm2, mm4 /* mult. 4 high words of Src and Kernel */ + paddsw mm1, mm2 /* add 4 words of the high and low bytes */ + paddsw mm7, mm1 /* add MM1 to accumulator MM7 */ + movq mm1, [esi] /* load 8 bytes of the Src */ + dec esi + add esi, eax /* move Src pointer 1 row below */ + movq mm3, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + punpcklbw mm1, mm0 /* unpack first 4 bytes into words */ + pmullw mm1, mm3 /* mult. 4 low words of Src and Kernel */ + paddsw mm7, mm1 /* add MM1 to accumulator MM7 */ + /* --- 2 */ + movq mm1, [esi] /* load 8 bytes of the Src */ + movq mm2, mm1 /* copy MM1 into MM2 */ + inc esi /* move pointer to the next 8 bytes of Src */ + movq mm3, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + movq mm4, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + punpcklbw mm1, mm0 /* unpack first 4 bytes into words */ + punpckhbw mm2, mm0 /* unpack second 4 bytes into words */ + pmullw mm1, mm3 /* mult. 4 low words of Src and Kernel */ + pmullw mm2, mm4 /* mult. 4 high words of Src and Kernel */ + paddsw mm1, mm2 /* add 4 words of the high and low bytes */ + paddsw mm7, mm1 /* add MM1 to accumulator MM7 */ + movq mm1, [esi] /* load 8 bytes of the Src */ + dec esi + add esi, eax /* move Src pointer 1 row below */ + movq mm3, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + punpcklbw mm1, mm0 /* unpack first 4 bytes into words */ + pmullw mm1, mm3 /* mult. 4 low words of Src and Kernel */ + paddsw mm7, mm1 /* add MM1 to accumulator MM7 */ + /* --- 3 */ + movq mm1, [esi] /* load 8 bytes of the Src */ + movq mm2, mm1 /* copy MM1 into MM2 */ + inc esi /* move pointer to the next 8 bytes of Src */ + movq mm3, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + movq mm4, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + punpcklbw mm1, mm0 /* unpack first 4 bytes into words */ + punpckhbw mm2, mm0 /* unpack second 4 bytes into words */ + pmullw mm1, mm3 /* mult. 4 low words of Src and Kernel */ + pmullw mm2, mm4 /* mult. 4 high words of Src and Kernel */ + paddsw mm1, mm2 /* add 4 words of the high and low bytes */ + paddsw mm7, mm1 /* add MM1 to accumulator MM7 */ + movq mm1, [esi] /* load 8 bytes of the Src */ + dec esi + add esi, eax /* move Src pointer 1 row below */ + movq mm3, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + punpcklbw mm1, mm0 /* unpack first 4 bytes into words */ + pmullw mm1, mm3 /* mult. 4 low words of Src and Kernel */ + paddsw mm7, mm1 /* add MM1 to accumulator MM7 */ + /* --- 4 */ + movq mm1, [esi] /* load 8 bytes of the Src */ + movq mm2, mm1 /* copy MM1 into MM2 */ + inc esi /* move pointer to the next 8 bytes of Src */ + movq mm3, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + movq mm4, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + punpcklbw mm1, mm0 /* unpack first 4 bytes into words */ + punpckhbw mm2, mm0 /* unpack second 4 bytes into words */ + pmullw mm1, mm3 /* mult. 4 low words of Src and Kernel */ + pmullw mm2, mm4 /* mult. 4 high words of Src and Kernel */ + paddsw mm1, mm2 /* add 4 words of the high and low bytes */ + paddsw mm7, mm1 /* add MM1 to accumulator MM7 */ + movq mm1, [esi] /* load 8 bytes of the Src */ + dec esi + add esi, eax /* move Src pointer 1 row below */ + movq mm3, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + punpcklbw mm1, mm0 /* unpack first 4 bytes into words */ + pmullw mm1, mm3 /* mult. 4 low words of Src and Kernel */ + paddsw mm7, mm1 /* add MM1 to accumulator MM7 */ + /* --- 5 */ + movq mm1, [esi] /* load 8 bytes of the Src */ + movq mm2, mm1 /* copy MM1 into MM2 */ + inc esi /* move pointer to the next 8 bytes of Src */ + movq mm3, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + movq mm4, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + punpcklbw mm1, mm0 /* unpack first 4 bytes into words */ + punpckhbw mm2, mm0 /* unpack second 4 bytes into words */ + pmullw mm1, mm3 /* mult. 4 low words of Src and Kernel */ + pmullw mm2, mm4 /* mult. 4 high words of Src and Kernel */ + paddsw mm1, mm2 /* add 4 words of the high and low bytes */ + paddsw mm7, mm1 /* add MM1 to accumulator MM7 */ + movq mm1, [esi] /* load 8 bytes of the Src */ + dec esi + add esi, eax /* move Src pointer 1 row below */ + movq mm3, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + punpcklbw mm1, mm0 /* unpack first 4 bytes into words */ + pmullw mm1, mm3 /* mult. 4 low words of Src and Kernel */ + paddsw mm7, mm1 /* add MM1 to accumulator MM7 */ + /* --- 6 */ + movq mm1, [esi] /* load 8 bytes of the Src */ + movq mm2, mm1 /* copy MM1 into MM2 */ + inc esi /* move pointer to the next 8 bytes of Src */ + movq mm3, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + movq mm4, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + punpcklbw mm1, mm0 /* unpack first 4 bytes into words */ + punpckhbw mm2, mm0 /* unpack second 4 bytes into words */ + pmullw mm1, mm3 /* mult. 4 low words of Src and Kernel */ + pmullw mm2, mm4 /* mult. 4 high words of Src and Kernel */ + paddsw mm1, mm2 /* add 4 words of the high and low bytes */ + paddsw mm7, mm1 /* add MM1 to accumulator MM7 */ + movq mm1, [esi] /* load 8 bytes of the Src */ + dec esi + add esi, eax /* move Src pointer 1 row below */ + movq mm3, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + punpcklbw mm1, mm0 /* unpack first 4 bytes into words */ + pmullw mm1, mm3 /* mult. 4 low words of Src and Kernel */ + paddsw mm7, mm1 /* add MM1 to accumulator MM7 */ + /* --- 7 */ + movq mm1, [esi] /* load 8 bytes of the Src */ + movq mm2, mm1 /* copy MM1 into MM2 */ + inc esi /* move pointer to the next 8 bytes of Src */ + movq mm3, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + movq mm4, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + punpcklbw mm1, mm0 /* unpack first 4 bytes into words */ + punpckhbw mm2, mm0 /* unpack second 4 bytes into words */ + pmullw mm1, mm3 /* mult. 4 low words of Src and Kernel */ + pmullw mm2, mm4 /* mult. 4 high words of Src and Kernel */ + paddsw mm1, mm2 /* add 4 words of the high and low bytes */ + paddsw mm7, mm1 /* add MM1 to accumulator MM7 */ + movq mm1, [esi] /* load 8 bytes of the Src */ + dec esi + add esi, eax /* move Src pointer 1 row below */ + movq mm3, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + punpcklbw mm1, mm0 /* unpack first 4 bytes into words */ + pmullw mm1, mm3 /* mult. 4 low words of Src and Kernel */ + paddsw mm7, mm1 /* add MM1 to accumulator MM7 */ + /* --- 8 */ + movq mm1, [esi] /* load 8 bytes of the Src */ + movq mm2, mm1 /* copy MM1 into MM2 */ + inc esi /* move pointer to the next 8 bytes of Src */ + movq mm3, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + movq mm4, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + punpcklbw mm1, mm0 /* unpack first 4 bytes into words */ + punpckhbw mm2, mm0 /* unpack second 4 bytes into words */ + pmullw mm1, mm3 /* mult. 4 low words of Src and Kernel */ + pmullw mm2, mm4 /* mult. 4 high words of Src and Kernel */ + paddsw mm1, mm2 /* add 4 words of the high and low bytes */ + paddsw mm7, mm1 /* add MM1 to accumulator MM7 */ + movq mm1, [esi] /* load 8 bytes of the Src */ + dec esi + add esi, eax /* move Src pointer 1 row below */ + movq mm3, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + punpcklbw mm1, mm0 /* unpack first 4 bytes into words */ + pmullw mm1, mm3 /* mult. 4 low words of Src and Kernel */ + paddsw mm7, mm1 /* add MM1 to accumulator MM7 */ + /* --- 9 */ + movq mm1, [esi] /* load 8 bytes of the Src */ + movq mm2, mm1 /* copy MM1 into MM2 */ + inc esi /* move pointer to the next 8 bytes of Src */ + movq mm3, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + movq mm4, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + punpcklbw mm1, mm0 /* unpack first 4 bytes into words */ + punpckhbw mm2, mm0 /* unpack second 4 bytes into words */ + pmullw mm1, mm3 /* mult. 4 low words of Src and Kernel */ + pmullw mm2, mm4 /* mult. 4 high words of Src and Kernel */ + paddsw mm1, mm2 /* add 4 words of the high and low bytes */ + paddsw mm7, mm1 /* add MM1 to accumulator MM7 */ + movq mm1, [esi] /* load 8 bytes of the Src */ + movq mm3, [edx] /* load 4 words of Kernel */ + punpcklbw mm1, mm0 /* unpack first 4 bytes into words */ + pmullw mm1, mm3 /* mult. 4 low words of Src and Kernel */ + paddsw mm7, mm1 /* add MM1 to accumulator MM7 */ + /* ---, */ + movq mm3, mm7 /* copy MM7 into MM3 */ + psrlq mm7, 32 /* shift 2 left words to the right */ + paddsw mm7, mm3 /* add 2 left and 2 right result words */ + movq mm2, mm7 /* copy MM7 into MM2 */ + psrlq mm7, 16 /* shift 1 left word to the right */ + paddsw mm7, mm2 /* add 1 left and 1 right result words */ + /* ---, */ + movd mm1, eax /* save EDX in MM1 */ + movd mm2, ebx /* save EDX in MM2 */ + movd mm3, edx /* save EDX in MM3 */ + movd eax, mm7 /* load summation result into EAX */ + psraw mm7, 15 /* spread sign bit of the result */ + movd ebx, mm5 /* load Divisor into EBX */ + movd edx, mm7 /* fill EDX with a sign bit */ + idiv bx /* IDIV - VERY EXPENSIVE */ + movd mm7, eax /* move result of division into MM7 */ + packuswb mm7, mm0 /* pack division result with saturation */ + movd eax, mm7 /* copy saturated result into EAX */ + mov [edi], al /* copy a byte result into Dest */ + movd edx, mm3 /* restore saved EDX */ + movd ebx, mm2 /* restore saved EBX */ + movd eax, mm1 /* restore saved EAX */ + /* --, */ + movd esi, mm6 /* move Src pointer to the top pixel */ + sub edx, 208 /* EDX = Kernel address */ + inc esi /* move Src pointer to the next pixel */ + inc edi /* move Dest pointer to the next pixel */ + /* ---, */ + dec ecx /* decrease loop counter COLUMNS */ + jnz L10352 /* check loop termination, proceed if required */ + add esi, 8 /* move to the next row in Src */ + add edi, 8 /* move to the next row in Dest */ + dec ebx /* decrease loop counter ROWS */ + jnz L10350 /* check loop termination, proceed if required */ + /* ---, */ + emms /* exit MMX state */ + popa + } +#else + asm volatile + ("pusha \n\t" "pxor %%mm0, %%mm0 \n\t" /* zero MM0 */ + "xor %%ebx, %%ebx \n\t" /* zero EBX */ + "mov %5, %%bl \n\t" /* load Divisor into BL */ + "movd %%ebx, %%mm5 \n\t" /* copy Divisor into MM5 */ + "mov %4, %%edx \n\t" /* load Kernel address into EDX */ + "mov %1, %%esi \n\t" /* load Src address to ESI */ + "mov %0, %%edi \n\t" /* load Dest address to EDI */ + "add $4, %%edi \n\t" /* 4 column offset from the left edge */ + "mov %3, %%eax \n\t" /* load columns into EAX */ + "add %%eax, %%edi \n\t" /* 4 row offset from the top edge */ + "add %%eax, %%edi \n\t" "add %%eax, %%edi \n\t" "add %%eax, %%edi \n\t" "mov %2, %%ebx \n\t" /* initialize ROWS counter */ + "sub $8, %%ebx \n\t" /* do not use first 4 and last 4 rows */ + /* --- */ + ".L10350: \n\t" "mov %%eax, %%ecx \n\t" /* initialize COLUMNS counter */ + "sub $8, %%ecx \n\t" /* do not use first 4 and last 4 columns */ + ".align 16 \n\t" /* 16 byte alignment of the loop entry */ + ".L10352: \n\t" "pxor %%mm7, %%mm7 \n\t" /* zero MM7 (accumulator) */ + "movd %%esi, %%mm6 \n\t" /* save ESI in MM6 */ + /* --- 1 */ + "movq (%%esi), %%mm1 \n\t" /* load 8 bytes of the Src */ + "movq %%mm1, %%mm2 \n\t" /* copy MM1 into MM2 */ + "inc %%esi \n\t" /* move pointer to the next 8 bytes of Src */ + "movq (%%edx), %%mm3 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "movq (%%edx), %%mm4 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "punpcklbw %%mm0, %%mm1 \n\t" /* unpack first 4 bytes into words */ + "punpckhbw %%mm0, %%mm2 \n\t" /* unpack second 4 bytes into words */ + "pmullw %%mm3, %%mm1 \n\t" /* mult. 4 low words of Src and Kernel */ + "pmullw %%mm4, %%mm2 \n\t" /* mult. 4 high words of Src and Kernel */ + "paddsw %%mm2, %%mm1 \n\t" /* add 4 words of the high and low bytes */ + "paddsw %%mm1, %%mm7 \n\t" /* add MM1 to accumulator MM7 */ + "movq (%%esi), %%mm1 \n\t" /* load 8 bytes of the Src */ + "dec %%esi \n\t" "add %%eax, %%esi \n\t" /* move Src pointer 1 row below */ + "movq (%%edx), %%mm3 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "punpcklbw %%mm0, %%mm1 \n\t" /* unpack first 4 bytes into words */ + "pmullw %%mm3, %%mm1 \n\t" /* mult. 4 low words of Src and Kernel */ + "paddsw %%mm1, %%mm7 \n\t" /* add MM1 to accumulator MM7 */ + /* --- 2 */ + "movq (%%esi), %%mm1 \n\t" /* load 8 bytes of the Src */ + "movq %%mm1, %%mm2 \n\t" /* copy MM1 into MM2 */ + "inc %%esi \n\t" /* move pointer to the next 8 bytes of Src */ + "movq (%%edx), %%mm3 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "movq (%%edx), %%mm4 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "punpcklbw %%mm0, %%mm1 \n\t" /* unpack first 4 bytes into words */ + "punpckhbw %%mm0, %%mm2 \n\t" /* unpack second 4 bytes into words */ + "pmullw %%mm3, %%mm1 \n\t" /* mult. 4 low words of Src and Kernel */ + "pmullw %%mm4, %%mm2 \n\t" /* mult. 4 high words of Src and Kernel */ + "paddsw %%mm2, %%mm1 \n\t" /* add 4 words of the high and low bytes */ + "paddsw %%mm1, %%mm7 \n\t" /* add MM1 to accumulator MM7 */ + "movq (%%esi), %%mm1 \n\t" /* load 8 bytes of the Src */ + "dec %%esi \n\t" "add %%eax, %%esi \n\t" /* move Src pointer 1 row below */ + "movq (%%edx), %%mm3 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "punpcklbw %%mm0, %%mm1 \n\t" /* unpack first 4 bytes into words */ + "pmullw %%mm3, %%mm1 \n\t" /* mult. 4 low words of Src and Kernel */ + "paddsw %%mm1, %%mm7 \n\t" /* add MM1 to accumulator MM7 */ + /* --- 3 */ + "movq (%%esi), %%mm1 \n\t" /* load 8 bytes of the Src */ + "movq %%mm1, %%mm2 \n\t" /* copy MM1 into MM2 */ + "inc %%esi \n\t" /* move pointer to the next 8 bytes of Src */ + "movq (%%edx), %%mm3 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "movq (%%edx), %%mm4 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "punpcklbw %%mm0, %%mm1 \n\t" /* unpack first 4 bytes into words */ + "punpckhbw %%mm0, %%mm2 \n\t" /* unpack second 4 bytes into words */ + "pmullw %%mm3, %%mm1 \n\t" /* mult. 4 low words of Src and Kernel */ + "pmullw %%mm4, %%mm2 \n\t" /* mult. 4 high words of Src and Kernel */ + "paddsw %%mm2, %%mm1 \n\t" /* add 4 words of the high and low bytes */ + "paddsw %%mm1, %%mm7 \n\t" /* add MM1 to accumulator MM7 */ + "movq (%%esi), %%mm1 \n\t" /* load 8 bytes of the Src */ + "dec %%esi \n\t" "add %%eax, %%esi \n\t" /* move Src pointer 1 row below */ + "movq (%%edx), %%mm3 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "punpcklbw %%mm0, %%mm1 \n\t" /* unpack first 4 bytes into words */ + "pmullw %%mm3, %%mm1 \n\t" /* mult. 4 low words of Src and Kernel */ + "paddsw %%mm1, %%mm7 \n\t" /* add MM1 to accumulator MM7 */ + /* --- 4 */ + "movq (%%esi), %%mm1 \n\t" /* load 8 bytes of the Src */ + "movq %%mm1, %%mm2 \n\t" /* copy MM1 into MM2 */ + "inc %%esi \n\t" /* move pointer to the next 8 bytes of Src */ + "movq (%%edx), %%mm3 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "movq (%%edx), %%mm4 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "punpcklbw %%mm0, %%mm1 \n\t" /* unpack first 4 bytes into words */ + "punpckhbw %%mm0, %%mm2 \n\t" /* unpack second 4 bytes into words */ + "pmullw %%mm3, %%mm1 \n\t" /* mult. 4 low words of Src and Kernel */ + "pmullw %%mm4, %%mm2 \n\t" /* mult. 4 high words of Src and Kernel */ + "paddsw %%mm2, %%mm1 \n\t" /* add 4 words of the high and low bytes */ + "paddsw %%mm1, %%mm7 \n\t" /* add MM1 to accumulator MM7 */ + "movq (%%esi), %%mm1 \n\t" /* load 8 bytes of the Src */ + "dec %%esi \n\t" "add %%eax, %%esi \n\t" /* move Src pointer 1 row below */ + "movq (%%edx), %%mm3 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "punpcklbw %%mm0, %%mm1 \n\t" /* unpack first 4 bytes into words */ + "pmullw %%mm3, %%mm1 \n\t" /* mult. 4 low words of Src and Kernel */ + "paddsw %%mm1, %%mm7 \n\t" /* add MM1 to accumulator MM7 */ + /* --- 5 */ + "movq (%%esi), %%mm1 \n\t" /* load 8 bytes of the Src */ + "movq %%mm1, %%mm2 \n\t" /* copy MM1 into MM2 */ + "inc %%esi \n\t" /* move pointer to the next 8 bytes of Src */ + "movq (%%edx), %%mm3 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "movq (%%edx), %%mm4 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "punpcklbw %%mm0, %%mm1 \n\t" /* unpack first 4 bytes into words */ + "punpckhbw %%mm0, %%mm2 \n\t" /* unpack second 4 bytes into words */ + "pmullw %%mm3, %%mm1 \n\t" /* mult. 4 low words of Src and Kernel */ + "pmullw %%mm4, %%mm2 \n\t" /* mult. 4 high words of Src and Kernel */ + "paddsw %%mm2, %%mm1 \n\t" /* add 4 words of the high and low bytes */ + "paddsw %%mm1, %%mm7 \n\t" /* add MM1 to accumulator MM7 */ + "movq (%%esi), %%mm1 \n\t" /* load 8 bytes of the Src */ + "dec %%esi \n\t" "add %%eax, %%esi \n\t" /* move Src pointer 1 row below */ + "movq (%%edx), %%mm3 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "punpcklbw %%mm0, %%mm1 \n\t" /* unpack first 4 bytes into words */ + "pmullw %%mm3, %%mm1 \n\t" /* mult. 4 low words of Src and Kernel */ + "paddsw %%mm1, %%mm7 \n\t" /* add MM1 to accumulator MM7 */ + /* --- 6 */ + "movq (%%esi), %%mm1 \n\t" /* load 8 bytes of the Src */ + "movq %%mm1, %%mm2 \n\t" /* copy MM1 into MM2 */ + "inc %%esi \n\t" /* move pointer to the next 8 bytes of Src */ + "movq (%%edx), %%mm3 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "movq (%%edx), %%mm4 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "punpcklbw %%mm0, %%mm1 \n\t" /* unpack first 4 bytes into words */ + "punpckhbw %%mm0, %%mm2 \n\t" /* unpack second 4 bytes into words */ + "pmullw %%mm3, %%mm1 \n\t" /* mult. 4 low words of Src and Kernel */ + "pmullw %%mm4, %%mm2 \n\t" /* mult. 4 high words of Src and Kernel */ + "paddsw %%mm2, %%mm1 \n\t" /* add 4 words of the high and low bytes */ + "paddsw %%mm1, %%mm7 \n\t" /* add MM1 to accumulator MM7 */ + "movq (%%esi), %%mm1 \n\t" /* load 8 bytes of the Src */ + "dec %%esi \n\t" "add %%eax, %%esi \n\t" /* move Src pointer 1 row below */ + "movq (%%edx), %%mm3 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "punpcklbw %%mm0, %%mm1 \n\t" /* unpack first 4 bytes into words */ + "pmullw %%mm3, %%mm1 \n\t" /* mult. 4 low words of Src and Kernel */ + "paddsw %%mm1, %%mm7 \n\t" /* add MM1 to accumulator MM7 */ + /* --- 7 */ + "movq (%%esi), %%mm1 \n\t" /* load 8 bytes of the Src */ + "movq %%mm1, %%mm2 \n\t" /* copy MM1 into MM2 */ + "inc %%esi \n\t" /* move pointer to the next 8 bytes of Src */ + "movq (%%edx), %%mm3 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "movq (%%edx), %%mm4 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "punpcklbw %%mm0, %%mm1 \n\t" /* unpack first 4 bytes into words */ + "punpckhbw %%mm0, %%mm2 \n\t" /* unpack second 4 bytes into words */ + "pmullw %%mm3, %%mm1 \n\t" /* mult. 4 low words of Src and Kernel */ + "pmullw %%mm4, %%mm2 \n\t" /* mult. 4 high words of Src and Kernel */ + "paddsw %%mm2, %%mm1 \n\t" /* add 4 words of the high and low bytes */ + "paddsw %%mm1, %%mm7 \n\t" /* add MM1 to accumulator MM7 */ + "movq (%%esi), %%mm1 \n\t" /* load 8 bytes of the Src */ + "dec %%esi \n\t" "add %%eax, %%esi \n\t" /* move Src pointer 1 row below */ + "movq (%%edx), %%mm3 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "punpcklbw %%mm0, %%mm1 \n\t" /* unpack first 4 bytes into words */ + "pmullw %%mm3, %%mm1 \n\t" /* mult. 4 low words of Src and Kernel */ + "paddsw %%mm1, %%mm7 \n\t" /* add MM1 to accumulator MM7 */ + /* --- 8 */ + "movq (%%esi), %%mm1 \n\t" /* load 8 bytes of the Src */ + "movq %%mm1, %%mm2 \n\t" /* copy MM1 into MM2 */ + "inc %%esi \n\t" /* move pointer to the next 8 bytes of Src */ + "movq (%%edx), %%mm3 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "movq (%%edx), %%mm4 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "punpcklbw %%mm0, %%mm1 \n\t" /* unpack first 4 bytes into words */ + "punpckhbw %%mm0, %%mm2 \n\t" /* unpack second 4 bytes into words */ + "pmullw %%mm3, %%mm1 \n\t" /* mult. 4 low words of Src and Kernel */ + "pmullw %%mm4, %%mm2 \n\t" /* mult. 4 high words of Src and Kernel */ + "paddsw %%mm2, %%mm1 \n\t" /* add 4 words of the high and low bytes */ + "paddsw %%mm1, %%mm7 \n\t" /* add MM1 to accumulator MM7 */ + "movq (%%esi), %%mm1 \n\t" /* load 8 bytes of the Src */ + "dec %%esi \n\t" "add %%eax, %%esi \n\t" /* move Src pointer 1 row below */ + "movq (%%edx), %%mm3 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "punpcklbw %%mm0, %%mm1 \n\t" /* unpack first 4 bytes into words */ + "pmullw %%mm3, %%mm1 \n\t" /* mult. 4 low words of Src and Kernel */ + "paddsw %%mm1, %%mm7 \n\t" /* add MM1 to accumulator MM7 */ + /* --- 9 */ + "movq (%%esi), %%mm1 \n\t" /* load 8 bytes of the Src */ + "movq %%mm1, %%mm2 \n\t" /* copy MM1 into MM2 */ + "inc %%esi \n\t" /* move pointer to the next 8 bytes of Src */ + "movq (%%edx), %%mm3 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "movq (%%edx), %%mm4 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "punpcklbw %%mm0, %%mm1 \n\t" /* unpack first 4 bytes into words */ + "punpckhbw %%mm0, %%mm2 \n\t" /* unpack second 4 bytes into words */ + "pmullw %%mm3, %%mm1 \n\t" /* mult. 4 low words of Src and Kernel */ + "pmullw %%mm4, %%mm2 \n\t" /* mult. 4 high words of Src and Kernel */ + "paddsw %%mm2, %%mm1 \n\t" /* add 4 words of the high and low bytes */ + "paddsw %%mm1, %%mm7 \n\t" /* add MM1 to accumulator MM7 */ + "movq (%%esi), %%mm1 \n\t" /* load 8 bytes of the Src */ + "movq (%%edx), %%mm3 \n\t" /* load 4 words of Kernel */ + "punpcklbw %%mm0, %%mm1 \n\t" /* unpack first 4 bytes into words */ + "pmullw %%mm3, %%mm1 \n\t" /* mult. 4 low words of Src and Kernel */ + "paddsw %%mm1, %%mm7 \n\t" /* add MM1 to accumulator MM7 */ + /* --- */ + "movq %%mm7, %%mm3 \n\t" /* copy MM7 into MM3 */ + "psrlq $32, %%mm7 \n\t" /* shift 2 left words to the right */ + "paddsw %%mm3, %%mm7 \n\t" /* add 2 left and 2 right result words */ + "movq %%mm7, %%mm2 \n\t" /* copy MM7 into MM2 */ + "psrlq $16, %%mm7 \n\t" /* shift 1 left word to the right */ + "paddsw %%mm2, %%mm7 \n\t" /* add 1 left and 1 right result words */ + /* --- */ + "movd %%eax, %%mm1 \n\t" /* save EDX in MM1 */ + "movd %%ebx, %%mm2 \n\t" /* save EDX in MM2 */ + "movd %%edx, %%mm3 \n\t" /* save EDX in MM3 */ + "movd %%mm7, %%eax \n\t" /* load summation result into EAX */ + "psraw $15, %%mm7 \n\t" /* spread sign bit of the result */ + "movd %%mm5, %%ebx \n\t" /* load Divisor into EBX */ + "movd %%mm7, %%edx \n\t" /* fill EDX with a sign bit */ + "idivw %%bx \n\t" /* IDIV - VERY EXPENSIVE */ + "movd %%eax, %%mm7 \n\t" /* move result of division into MM7 */ + "packuswb %%mm0, %%mm7 \n\t" /* pack division result with saturation */ + "movd %%mm7, %%eax \n\t" /* copy saturated result into EAX */ + "mov %%al, (%%edi) \n\t" /* copy a byte result into Dest */ + "movd %%mm3, %%edx \n\t" /* restore saved EDX */ + "movd %%mm2, %%ebx \n\t" /* restore saved EBX */ + "movd %%mm1, %%eax \n\t" /* restore saved EAX */ + /* -- */ + "movd %%mm6, %%esi \n\t" /* move Src pointer to the top pixel */ + "sub $208, %%edx \n\t" /* EDX = Kernel address */ + "inc %%esi \n\t" /* move Src pointer to the next pixel */ + "inc %%edi \n\t" /* move Dest pointer to the next pixel */ + /* --- */ + "dec %%ecx \n\t" /* decrease loop counter COLUMNS */ + "jnz .L10352 \n\t" /* check loop termination, proceed if required */ + "add $8, %%esi \n\t" /* move to the next row in Src */ + "add $8, %%edi \n\t" /* move to the next row in Dest */ + "dec %%ebx \n\t" /* decrease loop counter ROWS */ + "jnz .L10350 \n\t" /* check loop termination, proceed if required */ + /* --- */ + "emms \n\t" /* exit MMX state */ + "popa \n\t":"=m" (Dest) /* %0 */ + :"m"(Src), /* %1 */ + "m"(rows), /* %2 */ + "m"(columns), /* %3 */ + "m"(Kernel), /* %4 */ + "m"(Divisor) /* %5 */ + ); +#endif +#endif + return (0); + } else { + /* No non-MMX implementation yet */ + return (-1); + } +} + +/*! +\brief Filter using ConvolveKernel3x3ShiftRight: Dij = saturation0and255( ... ) + +\param Src The source 2D byte array to convolve. Should be different from destination. +\param Dest The destination 2D byte array to store the result in. Should be different from source. +\param rows Number of rows in source/destination array. Must be >2. +\param columns Number of columns in source/destination array. Must be >2. +\param Kernel The 2D convolution kernel of size 3x3. +\param NRightShift The number of right bit shifts to apply to the convolution sum. Must be <7. + +Note: Non-MMX implementation not available for this function. + +\return Returns 1 if filter was applied, 0 otherwise. +*/ +int SDL_imageFilterConvolveKernel3x3ShiftRight(unsigned char *Src, unsigned char *Dest, int rows, int columns, + signed short *Kernel, unsigned char NRightShift) +{ + /* Validate input parameters */ + if ((Src == NULL) || (Dest == NULL) || (Kernel == NULL)) + return(-1); + + if ((columns < 3) || (rows < 3) || (NRightShift > 7)) + return (-1); + + if ((SDL_imageFilterMMXdetect())) { +#ifdef USE_MMX +#if !defined(GCC__) + __asm + { + pusha + pxor mm0, mm0 /* zero MM0 */ + xor ebx, ebx /* zero EBX */ + mov bl, NRightShift /* load NRightShift into BL */ + movd mm4, ebx /* copy NRightShift into MM4 */ + mov edx, Kernel /* load Kernel address into EDX */ + movq mm5, [edx] /* MM5 = {0,K2,K1,K0} */ + add edx, 8 /* second row |K0 K1 K2 0| */ + movq mm6, [edx] /* MM6 = {0,K5,K4,K3} K = |K3 K4 K5 0| */ + add edx, 8 /* third row |K6 K7 K8 0| */ + movq mm7, [edx] /* MM7 = {0,K8,K7,K6} */ + /* ---, */ + mov eax, columns /* load columns into EAX */ + mov esi, Src /* ESI = Src row 0 address */ + mov edi, Dest /* load Dest address to EDI */ + add edi, eax /* EDI = EDI + columns */ + inc edi /* 1 byte offset from the left edge */ + mov edx, rows /* initialize ROWS counter */ + sub edx, 2 /* do not use first and last row */ + /* ---, */ +L10360: + mov ecx, eax /* initialize COLUMS counter */ + sub ecx, 2 /* do not use first and last column */ + align 16 /* 16 byte alignment of the loop entry */ +L10362: + /* ---, */ + movq mm1, [esi] /* load 8 bytes of the image first row */ + add esi, eax /* move one row below */ + movq mm2, [esi] /* load 8 bytes of the image second row */ + add esi, eax /* move one row below */ + movq mm3, [esi] /* load 8 bytes of the image third row */ + punpcklbw mm1, mm0 /* unpack first 4 bytes into words */ + punpcklbw mm2, mm0 /* unpack first 4 bytes into words */ + punpcklbw mm3, mm0 /* unpack first 4 bytes into words */ + psrlw mm1, mm4 /* shift right each pixel NshiftRight times */ + psrlw mm2, mm4 /* shift right each pixel NshiftRight times */ + psrlw mm3, mm4 /* shift right each pixel NshiftRight times */ + pmullw mm1, mm5 /* multiply words first row image*Kernel */ + pmullw mm2, mm6 /* multiply words second row image*Kernel */ + pmullw mm3, mm7 /* multiply words third row image*Kernel */ + paddsw mm1, mm2 /* add 4 words of the first and second rows */ + paddsw mm1, mm3 /* add 4 words of the third row and result */ + movq mm2, mm1 /* copy MM1 into MM2 */ + psrlq mm1, 32 /* shift 2 left words to the right */ + paddsw mm1, mm2 /* add 2 left and 2 right result words */ + movq mm3, mm1 /* copy MM1 into MM3 */ + psrlq mm1, 16 /* shift 1 left word to the right */ + paddsw mm1, mm3 /* add 1 left and 1 right result words */ + packuswb mm1, mm0 /* pack shift result with saturation */ + movd ebx, mm1 /* copy saturated result into EBX */ + mov [edi], bl /* copy a byte result into Dest */ + /* --, */ + sub esi, eax /* move two rows up */ + sub esi, eax + inc esi /* move Src pointer to the next pixel */ + inc edi /* move Dest pointer to the next pixel */ + /* ---, */ + dec ecx /* decrease loop counter COLUMNS */ + jnz L10362 /* check loop termination, proceed if required */ + add esi, 2 /* move to the next row in Src */ + add edi, 2 /* move to the next row in Dest */ + dec edx /* decrease loop counter ROWS */ + jnz L10360 /* check loop termination, proceed if required */ + /* ---, */ + emms /* exit MMX state */ + popa + } +#else + asm volatile + ("pusha \n\t" "pxor %%mm0, %%mm0 \n\t" /* zero MM0 */ + "xor %%ebx, %%ebx \n\t" /* zero EBX */ + "mov %5, %%bl \n\t" /* load NRightShift into BL */ + "movd %%ebx, %%mm4 \n\t" /* copy NRightShift into MM4 */ + "mov %4, %%edx \n\t" /* load Kernel address into EDX */ + "movq (%%edx), %%mm5 \n\t" /* MM5 = {0,K2,K1,K0} */ + "add $8, %%edx \n\t" /* second row |K0 K1 K2 0| */ + "movq (%%edx), %%mm6 \n\t" /* MM6 = {0,K5,K4,K3} K = |K3 K4 K5 0| */ + "add $8, %%edx \n\t" /* third row |K6 K7 K8 0| */ + "movq (%%edx), %%mm7 \n\t" /* MM7 = {0,K8,K7,K6} */ + /* --- */ + "mov %3, %%eax \n\t" /* load columns into EAX */ + "mov %1, %%esi \n\t" /* ESI = Src row 0 address */ + "mov %0, %%edi \n\t" /* load Dest address to EDI */ + "add %%eax, %%edi \n\t" /* EDI = EDI + columns */ + "inc %%edi \n\t" /* 1 byte offset from the left edge */ + "mov %2, %%edx \n\t" /* initialize ROWS counter */ + "sub $2, %%edx \n\t" /* do not use first and last row */ + /* --- */ + ".L10360: \n\t" "mov %%eax, %%ecx \n\t" /* initialize COLUMS counter */ + "sub $2, %%ecx \n\t" /* do not use first and last column */ + ".align 16 \n\t" /* 16 byte alignment of the loop entry */ + ".L10362: \n\t" + /* --- */ + "movq (%%esi), %%mm1 \n\t" /* load 8 bytes of the image first row */ + "add %%eax, %%esi \n\t" /* move one row below */ + "movq (%%esi), %%mm2 \n\t" /* load 8 bytes of the image second row */ + "add %%eax, %%esi \n\t" /* move one row below */ + "movq (%%esi), %%mm3 \n\t" /* load 8 bytes of the image third row */ + "punpcklbw %%mm0, %%mm1 \n\t" /* unpack first 4 bytes into words */ + "punpcklbw %%mm0, %%mm2 \n\t" /* unpack first 4 bytes into words */ + "punpcklbw %%mm0, %%mm3 \n\t" /* unpack first 4 bytes into words */ + "psrlw %%mm4, %%mm1 \n\t" /* shift right each pixel NshiftRight times */ + "psrlw %%mm4, %%mm2 \n\t" /* shift right each pixel NshiftRight times */ + "psrlw %%mm4, %%mm3 \n\t" /* shift right each pixel NshiftRight times */ + "pmullw %%mm5, %%mm1 \n\t" /* multiply words first row image*Kernel */ + "pmullw %%mm6, %%mm2 \n\t" /* multiply words second row image*Kernel */ + "pmullw %%mm7, %%mm3 \n\t" /* multiply words third row image*Kernel */ + "paddsw %%mm2, %%mm1 \n\t" /* add 4 words of the first and second rows */ + "paddsw %%mm3, %%mm1 \n\t" /* add 4 words of the third row and result */ + "movq %%mm1, %%mm2 \n\t" /* copy MM1 into MM2 */ + "psrlq $32, %%mm1 \n\t" /* shift 2 left words to the right */ + "paddsw %%mm2, %%mm1 \n\t" /* add 2 left and 2 right result words */ + "movq %%mm1, %%mm3 \n\t" /* copy MM1 into MM3 */ + "psrlq $16, %%mm1 \n\t" /* shift 1 left word to the right */ + "paddsw %%mm3, %%mm1 \n\t" /* add 1 left and 1 right result words */ + "packuswb %%mm0, %%mm1 \n\t" /* pack shift result with saturation */ + "movd %%mm1, %%ebx \n\t" /* copy saturated result into EBX */ + "mov %%bl, (%%edi) \n\t" /* copy a byte result into Dest */ + /* -- */ + "sub %%eax, %%esi \n\t" /* move two rows up */ + "sub %%eax, %%esi \n\t" "inc %%esi \n\t" /* move Src pointer to the next pixel */ + "inc %%edi \n\t" /* move Dest pointer to the next pixel */ + /* --- */ + "dec %%ecx \n\t" /* decrease loop counter COLUMNS */ + "jnz .L10362 \n\t" /* check loop termination, proceed if required */ + "add $2, %%esi \n\t" /* move to the next row in Src */ + "add $2, %%edi \n\t" /* move to the next row in Dest */ + "dec %%edx \n\t" /* decrease loop counter ROWS */ + "jnz .L10360 \n\t" /* check loop termination, proceed if required */ + /* --- */ + "emms \n\t" /* exit MMX state */ + "popa \n\t":"=m" (Dest) /* %0 */ + :"m"(Src), /* %1 */ + "m"(rows), /* %2 */ + "m"(columns), /* %3 */ + "m"(Kernel), /* %4 */ + "m"(NRightShift) /* %5 */ + ); +#endif +#endif + return (0); + } else { + /* No non-MMX implementation yet */ + return (-1); + } +} + +/*! +\brief Filter using ConvolveKernel5x5ShiftRight: Dij = saturation0and255( ... ) + +\param Src The source 2D byte array to convolve. Should be different from destination. +\param Dest The destination 2D byte array to store the result in. Should be different from source. +\param rows Number of rows in source/destination array. Must be >4. +\param columns Number of columns in source/destination array. Must be >4. +\param Kernel The 2D convolution kernel of size 5x5. +\param NRightShift The number of right bit shifts to apply to the convolution sum. Must be <7. + +Note: Non-MMX implementation not available for this function. + +\return Returns 1 if filter was applied, 0 otherwise. +*/ +int SDL_imageFilterConvolveKernel5x5ShiftRight(unsigned char *Src, unsigned char *Dest, int rows, int columns, + signed short *Kernel, unsigned char NRightShift) +{ + /* Validate input parameters */ + if ((Src == NULL) || (Dest == NULL) || (Kernel == NULL)) + return(-1); + + if ((columns < 5) || (rows < 5) || (NRightShift > 7)) + return (-1); + + if ((SDL_imageFilterMMXdetect())) { +#ifdef USE_MMX +#if !defined(GCC__) + __asm + { + pusha + pxor mm0, mm0 /* zero MM0 */ + xor ebx, ebx /* zero EBX */ + mov bl, NRightShift /* load NRightShift into BL */ + movd mm5, ebx /* copy NRightShift into MM5 */ + mov edx, Kernel /* load Kernel address into EDX */ + mov esi, Src /* load Src address to ESI */ + mov edi, Dest /* load Dest address to EDI */ + add edi, 2 /* 2 column offset from the left edge */ + mov eax, columns /* load columns into EAX */ + shl eax, 1 /* EAX = columns * 2 */ + add edi, eax /* 2 row offset from the top edge */ + shr eax, 1 /* EAX = columns */ + mov ebx, rows /* initialize ROWS counter */ + sub ebx, 4 /* do not use first 2 and last 2 rows */ + /* ---, */ +L10370: + mov ecx, eax /* initialize COLUMNS counter */ + sub ecx, 4 /* do not use first 2 and last 2 columns */ + align 16 /* 16 byte alignment of the loop entry */ +L10372: + pxor mm7, mm7 /* zero MM7 (accumulator) */ + movd mm6, esi /* save ESI in MM6 */ + /* --- 1 */ + movq mm1, [esi] /* load 8 bytes of the Src */ + movq mm2, mm1 /* copy MM1 into MM2 */ + add esi, eax /* move Src pointer 1 row below */ + movq mm3, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + movq mm4, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + punpcklbw mm1, mm0 /* unpack first 4 bytes into words */ + punpckhbw mm2, mm0 /* unpack second 4 bytes into words */ + psrlw mm1, mm5 /* shift right each pixel NshiftRight times */ + psrlw mm2, mm5 /* shift right each pixel NshiftRight times */ + pmullw mm1, mm3 /* mult 4 low words of Src and Kernel */ + pmullw mm2, mm4 /* mult 4 high words of Src and Kernel */ + paddsw mm1, mm2 /* add 4 words of the high and low bytes */ + paddsw mm7, mm1 /* add MM1 to accumulator MM7 */ + /* --- 2 */ + movq mm1, [esi] /* load 8 bytes of the Src */ + movq mm2, mm1 /* copy MM1 into MM2 */ + add esi, eax /* move Src pointer 1 row below */ + movq mm3, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + movq mm4, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + punpcklbw mm1, mm0 /* unpack first 4 bytes into words */ + punpckhbw mm2, mm0 /* unpack second 4 bytes into words */ + psrlw mm1, mm5 /* shift right each pixel NshiftRight times */ + psrlw mm2, mm5 /* shift right each pixel NshiftRight times */ + pmullw mm1, mm3 /* mult 4 low words of Src and Kernel */ + pmullw mm2, mm4 /* mult 4 high words of Src and Kernel */ + paddsw mm1, mm2 /* add 4 words of the high and low bytes */ + paddsw mm7, mm1 /* add MM1 to accumulator MM7 */ + /* --- 3 */ + movq mm1, [esi] /* load 8 bytes of the Src */ + movq mm2, mm1 /* copy MM1 into MM2 */ + add esi, eax /* move Src pointer 1 row below */ + movq mm3, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + movq mm4, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + punpcklbw mm1, mm0 /* unpack first 4 bytes into words */ + punpckhbw mm2, mm0 /* unpack second 4 bytes into words */ + psrlw mm1, mm5 /* shift right each pixel NshiftRight times */ + psrlw mm2, mm5 /* shift right each pixel NshiftRight times */ + pmullw mm1, mm3 /* mult 4 low words of Src and Kernel */ + pmullw mm2, mm4 /* mult 4 high words of Src and Kernel */ + paddsw mm1, mm2 /* add 4 words of the high and low bytes */ + paddsw mm7, mm1 /* add MM1 to accumulator MM7 */ + /* --- 4 */ + movq mm1, [esi] /* load 8 bytes of the Src */ + movq mm2, mm1 /* copy MM1 into MM2 */ + add esi, eax /* move Src pointer 1 row below */ + movq mm3, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + movq mm4, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + punpcklbw mm1, mm0 /* unpack first 4 bytes into words */ + punpckhbw mm2, mm0 /* unpack second 4 bytes into words */ + psrlw mm1, mm5 /* shift right each pixel NshiftRight times */ + psrlw mm2, mm5 /* shift right each pixel NshiftRight times */ + pmullw mm1, mm3 /* mult 4 low words of Src and Kernel */ + pmullw mm2, mm4 /* mult 4 high words of Src and Kernel */ + paddsw mm1, mm2 /* add 4 words of the high and low bytes */ + paddsw mm7, mm1 /* add MM1 to accumulator MM7 */ + /* --- 5 */ + movq mm1, [esi] /* load 8 bytes of the Src */ + movq mm2, mm1 /* copy MM1 into MM2 */ + movq mm3, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + movq mm4, [edx] /* load 4 words of Kernel */ + punpcklbw mm1, mm0 /* unpack first 4 bytes into words */ + punpckhbw mm2, mm0 /* unpack second 4 bytes into words */ + psrlw mm1, mm5 /* shift right each pixel NshiftRight times */ + psrlw mm2, mm5 /* shift right each pixel NshiftRight times */ + pmullw mm1, mm3 /* mult 4 low words of Src and Kernel */ + pmullw mm2, mm4 /* mult 4 high words of Src and Kernel */ + paddsw mm1, mm2 /* add 4 words of the high and low bytes */ + paddsw mm7, mm1 /* add MM1 to accumulator MM7 */ + /* ---, */ + movq mm3, mm7 /* copy MM7 into MM3 */ + psrlq mm7, 32 /* shift 2 left words to the right */ + paddsw mm7, mm3 /* add 2 left and 2 right result words */ + movq mm2, mm7 /* copy MM7 into MM2 */ + psrlq mm7, 16 /* shift 1 left word to the right */ + paddsw mm7, mm2 /* add 1 left and 1 right result words */ + movd mm1, eax /* save EAX in MM1 */ + packuswb mm7, mm0 /* pack division result with saturation */ + movd eax, mm7 /* copy saturated result into EAX */ + mov [edi], al /* copy a byte result into Dest */ + movd eax, mm1 /* restore saved EAX */ + /* --, */ + movd esi, mm6 /* move Src pointer to the top pixel */ + sub edx, 72 /* EDX = Kernel address */ + inc esi /* move Src pointer to the next pixel */ + inc edi /* move Dest pointer to the next pixel */ + /* ---, */ + dec ecx /* decrease loop counter COLUMNS */ + jnz L10372 /* check loop termination, proceed if required */ + add esi, 4 /* move to the next row in Src */ + add edi, 4 /* move to the next row in Dest */ + dec ebx /* decrease loop counter ROWS */ + jnz L10370 /* check loop termination, proceed if required */ + /* ---, */ + emms /* exit MMX state */ + popa + } +#else + asm volatile + ("pusha \n\t" "pxor %%mm0, %%mm0 \n\t" /* zero MM0 */ + "xor %%ebx, %%ebx \n\t" /* zero EBX */ + "mov %5, %%bl \n\t" /* load NRightShift into BL */ + "movd %%ebx, %%mm5 \n\t" /* copy NRightShift into MM5 */ + "mov %4, %%edx \n\t" /* load Kernel address into EDX */ + "mov %1, %%esi \n\t" /* load Src address to ESI */ + "mov %0, %%edi \n\t" /* load Dest address to EDI */ + "add $2, %%edi \n\t" /* 2 column offset from the left edge */ + "mov %3, %%eax \n\t" /* load columns into EAX */ + "shl $1, %%eax \n\t" /* EAX = columns * 2 */ + "add %%eax, %%edi \n\t" /* 2 row offset from the top edge */ + "shr $1, %%eax \n\t" /* EAX = columns */ + "mov %2, %%ebx \n\t" /* initialize ROWS counter */ + "sub $4, %%ebx \n\t" /* do not use first 2 and last 2 rows */ + /* --- */ + ".L10370: \n\t" "mov %%eax, %%ecx \n\t" /* initialize COLUMNS counter */ + "sub $4, %%ecx \n\t" /* do not use first 2 and last 2 columns */ + ".align 16 \n\t" /* 16 byte alignment of the loop entry */ + ".L10372: \n\t" "pxor %%mm7, %%mm7 \n\t" /* zero MM7 (accumulator) */ + "movd %%esi, %%mm6 \n\t" /* save ESI in MM6 */ + /* --- 1 */ + "movq (%%esi), %%mm1 \n\t" /* load 8 bytes of the Src */ + "movq %%mm1, %%mm2 \n\t" /* copy MM1 into MM2 */ + "add %%eax, %%esi \n\t" /* move Src pointer 1 row below */ + "movq (%%edx), %%mm3 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "movq (%%edx), %%mm4 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "punpcklbw %%mm0, %%mm1 \n\t" /* unpack first 4 bytes into words */ + "punpckhbw %%mm0, %%mm2 \n\t" /* unpack second 4 bytes into words */ + "psrlw %%mm5, %%mm1 \n\t" /* shift right each pixel NshiftRight times */ + "psrlw %%mm5, %%mm2 \n\t" /* shift right each pixel NshiftRight times */ + "pmullw %%mm3, %%mm1 \n\t" /* mult. 4 low words of Src and Kernel */ + "pmullw %%mm4, %%mm2 \n\t" /* mult. 4 high words of Src and Kernel */ + "paddsw %%mm2, %%mm1 \n\t" /* add 4 words of the high and low bytes */ + "paddsw %%mm1, %%mm7 \n\t" /* add MM1 to accumulator MM7 */ + /* --- 2 */ + "movq (%%esi), %%mm1 \n\t" /* load 8 bytes of the Src */ + "movq %%mm1, %%mm2 \n\t" /* copy MM1 into MM2 */ + "add %%eax, %%esi \n\t" /* move Src pointer 1 row below */ + "movq (%%edx), %%mm3 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "movq (%%edx), %%mm4 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "punpcklbw %%mm0, %%mm1 \n\t" /* unpack first 4 bytes into words */ + "punpckhbw %%mm0, %%mm2 \n\t" /* unpack second 4 bytes into words */ + "psrlw %%mm5, %%mm1 \n\t" /* shift right each pixel NshiftRight times */ + "psrlw %%mm5, %%mm2 \n\t" /* shift right each pixel NshiftRight times */ + "pmullw %%mm3, %%mm1 \n\t" /* mult. 4 low words of Src and Kernel */ + "pmullw %%mm4, %%mm2 \n\t" /* mult. 4 high words of Src and Kernel */ + "paddsw %%mm2, %%mm1 \n\t" /* add 4 words of the high and low bytes */ + "paddsw %%mm1, %%mm7 \n\t" /* add MM1 to accumulator MM7 */ + /* --- 3 */ + "movq (%%esi), %%mm1 \n\t" /* load 8 bytes of the Src */ + "movq %%mm1, %%mm2 \n\t" /* copy MM1 into MM2 */ + "add %%eax, %%esi \n\t" /* move Src pointer 1 row below */ + "movq (%%edx), %%mm3 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "movq (%%edx), %%mm4 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "punpcklbw %%mm0, %%mm1 \n\t" /* unpack first 4 bytes into words */ + "punpckhbw %%mm0, %%mm2 \n\t" /* unpack second 4 bytes into words */ + "psrlw %%mm5, %%mm1 \n\t" /* shift right each pixel NshiftRight times */ + "psrlw %%mm5, %%mm2 \n\t" /* shift right each pixel NshiftRight times */ + "pmullw %%mm3, %%mm1 \n\t" /* mult. 4 low words of Src and Kernel */ + "pmullw %%mm4, %%mm2 \n\t" /* mult. 4 high words of Src and Kernel */ + "paddsw %%mm2, %%mm1 \n\t" /* add 4 words of the high and low bytes */ + "paddsw %%mm1, %%mm7 \n\t" /* add MM1 to accumulator MM7 */ + /* --- 4 */ + "movq (%%esi), %%mm1 \n\t" /* load 8 bytes of the Src */ + "movq %%mm1, %%mm2 \n\t" /* copy MM1 into MM2 */ + "add %%eax, %%esi \n\t" /* move Src pointer 1 row below */ + "movq (%%edx), %%mm3 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "movq (%%edx), %%mm4 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "punpcklbw %%mm0, %%mm1 \n\t" /* unpack first 4 bytes into words */ + "punpckhbw %%mm0, %%mm2 \n\t" /* unpack second 4 bytes into words */ + "psrlw %%mm5, %%mm1 \n\t" /* shift right each pixel NshiftRight times */ + "psrlw %%mm5, %%mm2 \n\t" /* shift right each pixel NshiftRight times */ + "pmullw %%mm3, %%mm1 \n\t" /* mult. 4 low words of Src and Kernel */ + "pmullw %%mm4, %%mm2 \n\t" /* mult. 4 high words of Src and Kernel */ + "paddsw %%mm2, %%mm1 \n\t" /* add 4 words of the high and low bytes */ + "paddsw %%mm1, %%mm7 \n\t" /* add MM1 to accumulator MM7 */ + /* --- 5 */ + "movq (%%esi), %%mm1 \n\t" /* load 8 bytes of the Src */ + "movq %%mm1, %%mm2 \n\t" /* copy MM1 into MM2 */ + "movq (%%edx), %%mm3 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "movq (%%edx), %%mm4 \n\t" /* load 4 words of Kernel */ + "punpcklbw %%mm0, %%mm1 \n\t" /* unpack first 4 bytes into words */ + "punpckhbw %%mm0, %%mm2 \n\t" /* unpack second 4 bytes into words */ + "psrlw %%mm5, %%mm1 \n\t" /* shift right each pixel NshiftRight times */ + "psrlw %%mm5, %%mm2 \n\t" /* shift right each pixel NshiftRight times */ + "pmullw %%mm3, %%mm1 \n\t" /* mult. 4 low words of Src and Kernel */ + "pmullw %%mm4, %%mm2 \n\t" /* mult. 4 high words of Src and Kernel */ + "paddsw %%mm2, %%mm1 \n\t" /* add 4 words of the high and low bytes */ + "paddsw %%mm1, %%mm7 \n\t" /* add MM1 to accumulator MM7 */ + /* --- */ + "movq %%mm7, %%mm3 \n\t" /* copy MM7 into MM3 */ + "psrlq $32, %%mm7 \n\t" /* shift 2 left words to the right */ + "paddsw %%mm3, %%mm7 \n\t" /* add 2 left and 2 right result words */ + "movq %%mm7, %%mm2 \n\t" /* copy MM7 into MM2 */ + "psrlq $16, %%mm7 \n\t" /* shift 1 left word to the right */ + "paddsw %%mm2, %%mm7 \n\t" /* add 1 left and 1 right result words */ + "movd %%eax, %%mm1 \n\t" /* save EAX in MM1 */ + "packuswb %%mm0, %%mm7 \n\t" /* pack division result with saturation */ + "movd %%mm7, %%eax \n\t" /* copy saturated result into EAX */ + "mov %%al, (%%edi) \n\t" /* copy a byte result into Dest */ + "movd %%mm1, %%eax \n\t" /* restore saved EAX */ + /* -- */ + "movd %%mm6, %%esi \n\t" /* move Src pointer to the top pixel */ + "sub $72, %%edx \n\t" /* EDX = Kernel address */ + "inc %%esi \n\t" /* move Src pointer to the next pixel */ + "inc %%edi \n\t" /* move Dest pointer to the next pixel */ + /* --- */ + "dec %%ecx \n\t" /* decrease loop counter COLUMNS */ + "jnz .L10372 \n\t" /* check loop termination, proceed if required */ + "add $4, %%esi \n\t" /* move to the next row in Src */ + "add $4, %%edi \n\t" /* move to the next row in Dest */ + "dec %%ebx \n\t" /* decrease loop counter ROWS */ + "jnz .L10370 \n\t" /* check loop termination, proceed if required */ + /* --- */ + "emms \n\t" /* exit MMX state */ + "popa \n\t":"=m" (Dest) /* %0 */ + :"m"(Src), /* %1 */ + "m"(rows), /* %2 */ + "m"(columns), /* %3 */ + "m"(Kernel), /* %4 */ + "m"(NRightShift) /* %5 */ + ); +#endif +#endif + return (0); + } else { + /* No non-MMX implementation yet */ + return (-1); + } +} + +/*! +\brief Filter using ConvolveKernel7x7ShiftRight: Dij = saturation0and255( ... ) + +\param Src The source 2D byte array to convolve. Should be different from destination. +\param Dest The destination 2D byte array to store the result in. Should be different from source. +\param rows Number of rows in source/destination array. Must be >6. +\param columns Number of columns in source/destination array. Must be >6. +\param Kernel The 2D convolution kernel of size 7x7. +\param NRightShift The number of right bit shifts to apply to the convolution sum. Must be <7. + +Note: Non-MMX implementation not available for this function. + +\return Returns 1 if filter was applied, 0 otherwise. +*/ +int SDL_imageFilterConvolveKernel7x7ShiftRight(unsigned char *Src, unsigned char *Dest, int rows, int columns, + signed short *Kernel, unsigned char NRightShift) +{ + /* Validate input parameters */ + if ((Src == NULL) || (Dest == NULL) || (Kernel == NULL)) + return(-1); + + if ((columns < 7) || (rows < 7) || (NRightShift > 7)) + return (-1); + + if ((SDL_imageFilterMMXdetect())) { +#ifdef USE_MMX +#if !defined(GCC__) + __asm + { + pusha + pxor mm0, mm0 /* zero MM0 */ + xor ebx, ebx /* zero EBX */ + mov bl, NRightShift /* load NRightShift into BL */ + movd mm5, ebx /* copy NRightShift into MM5 */ + mov edx, Kernel /* load Kernel address into EDX */ + mov esi, Src /* load Src address to ESI */ + mov edi, Dest /* load Dest address to EDI */ + add edi, 3 /* 3 column offset from the left edge */ + mov eax, columns /* load columns into EAX */ + add edi, eax /* 3 row offset from the top edge */ + add edi, eax + add edi, eax + mov ebx, rows /* initialize ROWS counter */ + sub ebx, 6 /* do not use first 3 and last 3 rows */ + /* ---, */ +L10380: + mov ecx, eax /* initialize COLUMNS counter */ + sub ecx, 6 /* do not use first 3 and last 3 columns */ + align 16 /* 16 byte alignment of the loop entry */ +L10382: + pxor mm7, mm7 /* zero MM7 (accumulator) */ + movd mm6, esi /* save ESI in MM6 */ + /* --- 1 */ + movq mm1, [esi] /* load 8 bytes of the Src */ + movq mm2, mm1 /* copy MM1 into MM2 */ + add esi, eax /* move Src pointer 1 row below */ + movq mm3, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + movq mm4, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + punpcklbw mm1, mm0 /* unpack first 4 bytes into words */ + punpckhbw mm2, mm0 /* unpack second 4 bytes into words */ + psrlw mm1, mm5 /* shift right each pixel NshiftRight times */ + psrlw mm2, mm5 /* shift right each pixel NshiftRight times */ + pmullw mm1, mm3 /* mult 4 low words of Src and Kernel */ + pmullw mm2, mm4 /* mult 4 high words of Src and Kernel */ + paddsw mm1, mm2 /* add 4 words of the high and low bytes */ + paddsw mm7, mm1 /* add MM1 to accumulator MM7 */ + /* --- 2 */ + movq mm1, [esi] /* load 8 bytes of the Src */ + movq mm2, mm1 /* copy MM1 into MM2 */ + add esi, eax /* move Src pointer 1 row below */ + movq mm3, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + movq mm4, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + punpcklbw mm1, mm0 /* unpack first 4 bytes into words */ + punpckhbw mm2, mm0 /* unpack second 4 bytes into words */ + psrlw mm1, mm5 /* shift right each pixel NshiftRight times */ + psrlw mm2, mm5 /* shift right each pixel NshiftRight times */ + pmullw mm1, mm3 /* mult 4 low words of Src and Kernel */ + pmullw mm2, mm4 /* mult 4 high words of Src and Kernel */ + paddsw mm1, mm2 /* add 4 words of the high and low bytes */ + paddsw mm7, mm1 /* add MM1 to accumulator MM7 */ + /* --- 3 */ + movq mm1, [esi] /* load 8 bytes of the Src */ + movq mm2, mm1 /* copy MM1 into MM2 */ + add esi, eax /* move Src pointer 1 row below */ + movq mm3, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + movq mm4, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + punpcklbw mm1, mm0 /* unpack first 4 bytes into words */ + punpckhbw mm2, mm0 /* unpack second 4 bytes into words */ + psrlw mm1, mm5 /* shift right each pixel NshiftRight times */ + psrlw mm2, mm5 /* shift right each pixel NshiftRight times */ + pmullw mm1, mm3 /* mult 4 low words of Src and Kernel */ + pmullw mm2, mm4 /* mult 4 high words of Src and Kernel */ + paddsw mm1, mm2 /* add 4 words of the high and low bytes */ + paddsw mm7, mm1 /* add MM1 to accumulator MM7 */ + /* --- 4 */ + movq mm1, [esi] /* load 8 bytes of the Src */ + movq mm2, mm1 /* copy MM1 into MM2 */ + add esi, eax /* move Src pointer 1 row below */ + movq mm3, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + movq mm4, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + punpcklbw mm1, mm0 /* unpack first 4 bytes into words */ + punpckhbw mm2, mm0 /* unpack second 4 bytes into words */ + psrlw mm1, mm5 /* shift right each pixel NshiftRight times */ + psrlw mm2, mm5 /* shift right each pixel NshiftRight times */ + pmullw mm1, mm3 /* mult 4 low words of Src and Kernel */ + pmullw mm2, mm4 /* mult 4 high words of Src and Kernel */ + paddsw mm1, mm2 /* add 4 words of the high and low bytes */ + paddsw mm7, mm1 /* add MM1 to accumulator MM7 */ + /* --- 5 */ + movq mm1, [esi] /* load 8 bytes of the Src */ + movq mm2, mm1 /* copy MM1 into MM2 */ + add esi, eax /* move Src pointer 1 row below */ + movq mm3, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + movq mm4, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + punpcklbw mm1, mm0 /* unpack first 4 bytes into words */ + punpckhbw mm2, mm0 /* unpack second 4 bytes into words */ + psrlw mm1, mm5 /* shift right each pixel NshiftRight times */ + psrlw mm2, mm5 /* shift right each pixel NshiftRight times */ + pmullw mm1, mm3 /* mult 4 low words of Src and Kernel */ + pmullw mm2, mm4 /* mult 4 high words of Src and Kernel */ + paddsw mm1, mm2 /* add 4 words of the high and low bytes */ + paddsw mm7, mm1 /* add MM1 to accumulator MM7 */ + /* --- 6 */ + movq mm1, [esi] /* load 8 bytes of the Src */ + movq mm2, mm1 /* copy MM1 into MM2 */ + add esi, eax /* move Src pointer 1 row below */ + movq mm3, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + movq mm4, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + punpcklbw mm1, mm0 /* unpack first 4 bytes into words */ + punpckhbw mm2, mm0 /* unpack second 4 bytes into words */ + psrlw mm1, mm5 /* shift right each pixel NshiftRight times */ + psrlw mm2, mm5 /* shift right each pixel NshiftRight times */ + pmullw mm1, mm3 /* mult 4 low words of Src and Kernel */ + pmullw mm2, mm4 /* mult 4 high words of Src and Kernel */ + paddsw mm1, mm2 /* add 4 words of the high and low bytes */ + paddsw mm7, mm1 /* add MM1 to accumulator MM7 */ + /* --- 7 */ + movq mm1, [esi] /* load 8 bytes of the Src */ + movq mm2, mm1 /* copy MM1 into MM2 */ + movq mm3, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + movq mm4, [edx] /* load 4 words of Kernel */ + punpcklbw mm1, mm0 /* unpack first 4 bytes into words */ + punpckhbw mm2, mm0 /* unpack second 4 bytes into words */ + psrlw mm1, mm5 /* shift right each pixel NshiftRight times */ + psrlw mm2, mm5 /* shift right each pixel NshiftRight times */ + pmullw mm1, mm3 /* mult 4 low words of Src and Kernel */ + pmullw mm2, mm4 /* mult 4 high words of Src and Kernel */ + paddsw mm1, mm2 /* add 4 words of the high and low bytes */ + paddsw mm7, mm1 /* add MM1 to accumulator MM7 */ + /* ---, */ + movq mm3, mm7 /* copy MM7 into MM3 */ + psrlq mm7, 32 /* shift 2 left words to the right */ + paddsw mm7, mm3 /* add 2 left and 2 right result words */ + movq mm2, mm7 /* copy MM7 into MM2 */ + psrlq mm7, 16 /* shift 1 left word to the right */ + paddsw mm7, mm2 /* add 1 left and 1 right result words */ + movd mm1, eax /* save EAX in MM1 */ + packuswb mm7, mm0 /* pack division result with saturation */ + movd eax, mm7 /* copy saturated result into EAX */ + mov [edi], al /* copy a byte result into Dest */ + movd eax, mm1 /* restore saved EAX */ + /* --, */ + movd esi, mm6 /* move Src pointer to the top pixel */ + sub edx, 104 /* EDX = Kernel address */ + inc esi /* move Src pointer to the next pixel */ + inc edi /* move Dest pointer to the next pixel */ + /* ---, */ + dec ecx /* decrease loop counter COLUMNS */ + jnz L10382 /* check loop termination, proceed if required */ + add esi, 6 /* move to the next row in Src */ + add edi, 6 /* move to the next row in Dest */ + dec ebx /* decrease loop counter ROWS */ + jnz L10380 /* check loop termination, proceed if required */ + /* ---, */ + emms /* exit MMX state */ + popa + } +#else + asm volatile + ("pusha \n\t" "pxor %%mm0, %%mm0 \n\t" /* zero MM0 */ + "xor %%ebx, %%ebx \n\t" /* zero EBX */ + "mov %5, %%bl \n\t" /* load NRightShift into BL */ + "movd %%ebx, %%mm5 \n\t" /* copy NRightShift into MM5 */ + "mov %4, %%edx \n\t" /* load Kernel address into EDX */ + "mov %1, %%esi \n\t" /* load Src address to ESI */ + "mov %0, %%edi \n\t" /* load Dest address to EDI */ + "add $3, %%edi \n\t" /* 3 column offset from the left edge */ + "mov %3, %%eax \n\t" /* load columns into EAX */ + "add %%eax, %%edi \n\t" /* 3 row offset from the top edge */ + "add %%eax, %%edi \n\t" "add %%eax, %%edi \n\t" "mov %2, %%ebx \n\t" /* initialize ROWS counter */ + "sub $6, %%ebx \n\t" /* do not use first 3 and last 3 rows */ + /* --- */ + ".L10380: \n\t" "mov %%eax, %%ecx \n\t" /* initialize COLUMNS counter */ + "sub $6, %%ecx \n\t" /* do not use first 3 and last 3 columns */ + ".align 16 \n\t" /* 16 byte alignment of the loop entry */ + ".L10382: \n\t" "pxor %%mm7, %%mm7 \n\t" /* zero MM7 (accumulator) */ + "movd %%esi, %%mm6 \n\t" /* save ESI in MM6 */ + /* --- 1 */ + "movq (%%esi), %%mm1 \n\t" /* load 8 bytes of the Src */ + "movq %%mm1, %%mm2 \n\t" /* copy MM1 into MM2 */ + "add %%eax, %%esi \n\t" /* move Src pointer 1 row below */ + "movq (%%edx), %%mm3 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "movq (%%edx), %%mm4 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "punpcklbw %%mm0, %%mm1 \n\t" /* unpack first 4 bytes into words */ + "punpckhbw %%mm0, %%mm2 \n\t" /* unpack second 4 bytes into words */ + "psrlw %%mm5, %%mm1 \n\t" /* shift right each pixel NshiftRight times */ + "psrlw %%mm5, %%mm2 \n\t" /* shift right each pixel NshiftRight times */ + "pmullw %%mm3, %%mm1 \n\t" /* mult. 4 low words of Src and Kernel */ + "pmullw %%mm4, %%mm2 \n\t" /* mult. 4 high words of Src and Kernel */ + "paddsw %%mm2, %%mm1 \n\t" /* add 4 words of the high and low bytes */ + "paddsw %%mm1, %%mm7 \n\t" /* add MM1 to accumulator MM7 */ + /* --- 2 */ + "movq (%%esi), %%mm1 \n\t" /* load 8 bytes of the Src */ + "movq %%mm1, %%mm2 \n\t" /* copy MM1 into MM2 */ + "add %%eax, %%esi \n\t" /* move Src pointer 1 row below */ + "movq (%%edx), %%mm3 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "movq (%%edx), %%mm4 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "punpcklbw %%mm0, %%mm1 \n\t" /* unpack first 4 bytes into words */ + "punpckhbw %%mm0, %%mm2 \n\t" /* unpack second 4 bytes into words */ + "psrlw %%mm5, %%mm1 \n\t" /* shift right each pixel NshiftRight times */ + "psrlw %%mm5, %%mm2 \n\t" /* shift right each pixel NshiftRight times */ + "pmullw %%mm3, %%mm1 \n\t" /* mult. 4 low words of Src and Kernel */ + "pmullw %%mm4, %%mm2 \n\t" /* mult. 4 high words of Src and Kernel */ + "paddsw %%mm2, %%mm1 \n\t" /* add 4 words of the high and low bytes */ + "paddsw %%mm1, %%mm7 \n\t" /* add MM1 to accumulator MM7 */ + /* --- 3 */ + "movq (%%esi), %%mm1 \n\t" /* load 8 bytes of the Src */ + "movq %%mm1, %%mm2 \n\t" /* copy MM1 into MM2 */ + "add %%eax, %%esi \n\t" /* move Src pointer 1 row below */ + "movq (%%edx), %%mm3 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "movq (%%edx), %%mm4 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "punpcklbw %%mm0, %%mm1 \n\t" /* unpack first 4 bytes into words */ + "punpckhbw %%mm0, %%mm2 \n\t" /* unpack second 4 bytes into words */ + "psrlw %%mm5, %%mm1 \n\t" /* shift right each pixel NshiftRight times */ + "psrlw %%mm5, %%mm2 \n\t" /* shift right each pixel NshiftRight times */ + "pmullw %%mm3, %%mm1 \n\t" /* mult. 4 low words of Src and Kernel */ + "pmullw %%mm4, %%mm2 \n\t" /* mult. 4 high words of Src and Kernel */ + "paddsw %%mm2, %%mm1 \n\t" /* add 4 words of the high and low bytes */ + "paddsw %%mm1, %%mm7 \n\t" /* add MM1 to accumulator MM7 */ + /* --- 4 */ + "movq (%%esi), %%mm1 \n\t" /* load 8 bytes of the Src */ + "movq %%mm1, %%mm2 \n\t" /* copy MM1 into MM2 */ + "add %%eax, %%esi \n\t" /* move Src pointer 1 row below */ + "movq (%%edx), %%mm3 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "movq (%%edx), %%mm4 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "punpcklbw %%mm0, %%mm1 \n\t" /* unpack first 4 bytes into words */ + "punpckhbw %%mm0, %%mm2 \n\t" /* unpack second 4 bytes into words */ + "psrlw %%mm5, %%mm1 \n\t" /* shift right each pixel NshiftRight times */ + "psrlw %%mm5, %%mm2 \n\t" /* shift right each pixel NshiftRight times */ + "pmullw %%mm3, %%mm1 \n\t" /* mult. 4 low words of Src and Kernel */ + "pmullw %%mm4, %%mm2 \n\t" /* mult. 4 high words of Src and Kernel */ + "paddsw %%mm2, %%mm1 \n\t" /* add 4 words of the high and low bytes */ + "paddsw %%mm1, %%mm7 \n\t" /* add MM1 to accumulator MM7 */ + /* --- 5 */ + "movq (%%esi), %%mm1 \n\t" /* load 8 bytes of the Src */ + "movq %%mm1, %%mm2 \n\t" /* copy MM1 into MM2 */ + "add %%eax, %%esi \n\t" /* move Src pointer 1 row below */ + "movq (%%edx), %%mm3 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "movq (%%edx), %%mm4 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "punpcklbw %%mm0, %%mm1 \n\t" /* unpack first 4 bytes into words */ + "punpckhbw %%mm0, %%mm2 \n\t" /* unpack second 4 bytes into words */ + "psrlw %%mm5, %%mm1 \n\t" /* shift right each pixel NshiftRight times */ + "psrlw %%mm5, %%mm2 \n\t" /* shift right each pixel NshiftRight times */ + "pmullw %%mm3, %%mm1 \n\t" /* mult. 4 low words of Src and Kernel */ + "pmullw %%mm4, %%mm2 \n\t" /* mult. 4 high words of Src and Kernel */ + "paddsw %%mm2, %%mm1 \n\t" /* add 4 words of the high and low bytes */ + "paddsw %%mm1, %%mm7 \n\t" /* add MM1 to accumulator MM7 */ + /* --- 6 */ + "movq (%%esi), %%mm1 \n\t" /* load 8 bytes of the Src */ + "movq %%mm1, %%mm2 \n\t" /* copy MM1 into MM2 */ + "add %%eax, %%esi \n\t" /* move Src pointer 1 row below */ + "movq (%%edx), %%mm3 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "movq (%%edx), %%mm4 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "punpcklbw %%mm0, %%mm1 \n\t" /* unpack first 4 bytes into words */ + "punpckhbw %%mm0, %%mm2 \n\t" /* unpack second 4 bytes into words */ + "psrlw %%mm5, %%mm1 \n\t" /* shift right each pixel NshiftRight times */ + "psrlw %%mm5, %%mm2 \n\t" /* shift right each pixel NshiftRight times */ + "pmullw %%mm3, %%mm1 \n\t" /* mult. 4 low words of Src and Kernel */ + "pmullw %%mm4, %%mm2 \n\t" /* mult. 4 high words of Src and Kernel */ + "paddsw %%mm2, %%mm1 \n\t" /* add 4 words of the high and low bytes */ + "paddsw %%mm1, %%mm7 \n\t" /* add MM1 to accumulator MM7 */ + /* --- 7 */ + "movq (%%esi), %%mm1 \n\t" /* load 8 bytes of the Src */ + "movq %%mm1, %%mm2 \n\t" /* copy MM1 into MM2 */ + "movq (%%edx), %%mm3 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "movq (%%edx), %%mm4 \n\t" /* load 4 words of Kernel */ + "punpcklbw %%mm0, %%mm1 \n\t" /* unpack first 4 bytes into words */ + "punpckhbw %%mm0, %%mm2 \n\t" /* unpack second 4 bytes into words */ + "psrlw %%mm5, %%mm1 \n\t" /* shift right each pixel NshiftRight times */ + "psrlw %%mm5, %%mm2 \n\t" /* shift right each pixel NshiftRight times */ + "pmullw %%mm3, %%mm1 \n\t" /* mult. 4 low words of Src and Kernel */ + "pmullw %%mm4, %%mm2 \n\t" /* mult. 4 high words of Src and Kernel */ + "paddsw %%mm2, %%mm1 \n\t" /* add 4 words of the high and low bytes */ + "paddsw %%mm1, %%mm7 \n\t" /* add MM1 to accumulator MM7 */ + /* --- */ + "movq %%mm7, %%mm3 \n\t" /* copy MM7 into MM3 */ + "psrlq $32, %%mm7 \n\t" /* shift 2 left words to the right */ + "paddsw %%mm3, %%mm7 \n\t" /* add 2 left and 2 right result words */ + "movq %%mm7, %%mm2 \n\t" /* copy MM7 into MM2 */ + "psrlq $16, %%mm7 \n\t" /* shift 1 left word to the right */ + "paddsw %%mm2, %%mm7 \n\t" /* add 1 left and 1 right result words */ + "movd %%eax, %%mm1 \n\t" /* save EAX in MM1 */ + "packuswb %%mm0, %%mm7 \n\t" /* pack division result with saturation */ + "movd %%mm7, %%eax \n\t" /* copy saturated result into EAX */ + "mov %%al, (%%edi) \n\t" /* copy a byte result into Dest */ + "movd %%mm1, %%eax \n\t" /* restore saved EAX */ + /* -- */ + "movd %%mm6, %%esi \n\t" /* move Src pointer to the top pixel */ + "sub $104, %%edx \n\t" /* EDX = Kernel address */ + "inc %%esi \n\t" /* move Src pointer to the next pixel */ + "inc %%edi \n\t" /* move Dest pointer to the next pixel */ + /* --- */ + "dec %%ecx \n\t" /* decrease loop counter COLUMNS */ + "jnz .L10382 \n\t" /* check loop termination, proceed if required */ + "add $6, %%esi \n\t" /* move to the next row in Src */ + "add $6, %%edi \n\t" /* move to the next row in Dest */ + "dec %%ebx \n\t" /* decrease loop counter ROWS */ + "jnz .L10380 \n\t" /* check loop termination, proceed if required */ + /* --- */ + "emms \n\t" /* exit MMX state */ + "popa \n\t":"=m" (Dest) /* %0 */ + :"m"(Src), /* %1 */ + "m"(rows), /* %2 */ + "m"(columns), /* %3 */ + "m"(Kernel), /* %4 */ + "m"(NRightShift) /* %5 */ + ); +#endif +#endif + return (0); + } else { + /* No non-MMX implementation yet */ + return (-1); + } +} + +/*! +\brief Filter using ConvolveKernel9x9ShiftRight: Dij = saturation255( ... ) + +\param Src The source 2D byte array to convolve. Should be different from destination. +\param Dest The destination 2D byte array to store the result in. Should be different from source. +\param rows Number of rows in source/destination array. Must be >8. +\param columns Number of columns in source/destination array. Must be >8. +\param Kernel The 2D convolution kernel of size 9x9. +\param NRightShift The number of right bit shifts to apply to the convolution sum. Must be <7. + +Note: Non-MMX implementation not available for this function. + +\return Returns 1 if filter was applied, 0 otherwise. +*/ +int SDL_imageFilterConvolveKernel9x9ShiftRight(unsigned char *Src, unsigned char *Dest, int rows, int columns, + signed short *Kernel, unsigned char NRightShift) +{ + /* Validate input parameters */ + if ((Src == NULL) || (Dest == NULL) || (Kernel == NULL)) + return(-1); + + if ((columns < 9) || (rows < 9) || (NRightShift > 7)) + return (-1); + + if ((SDL_imageFilterMMXdetect())) { +#ifdef USE_MMX +#if !defined(GCC__) + __asm + { + pusha + pxor mm0, mm0 /* zero MM0 */ + xor ebx, ebx /* zero EBX */ + mov bl, NRightShift /* load NRightShift into BL */ + movd mm5, ebx /* copy NRightShift into MM5 */ + mov edx, Kernel /* load Kernel address into EDX */ + mov esi, Src /* load Src address to ESI */ + mov edi, Dest /* load Dest address to EDI */ + add edi, 4 /* 4 column offset from the left edge */ + mov eax, columns /* load columns into EAX */ + add edi, eax /* 4 row offset from the top edge */ + add edi, eax + add edi, eax + add edi, eax + mov ebx, rows /* initialize ROWS counter */ + sub ebx, 8 /* do not use first 4 and last 4 rows */ + /* ---, */ +L10390: + mov ecx, eax /* initialize COLUMNS counter */ + sub ecx, 8 /* do not use first 4 and last 4 columns */ + align 16 /* 16 byte alignment of the loop entry */ +L10392: + pxor mm7, mm7 /* zero MM7 (accumulator) */ + movd mm6, esi /* save ESI in MM6 */ + /* --- 1 */ + movq mm1, [esi] /* load 8 bytes of the Src */ + movq mm2, mm1 /* copy MM1 into MM2 */ + inc esi /* move pointer to the next 8 bytes of Src */ + movq mm3, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + movq mm4, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + punpcklbw mm1, mm0 /* unpack first 4 bytes into words */ + punpckhbw mm2, mm0 /* unpack second 4 bytes into words */ + psrlw mm1, mm5 /* shift right each pixel NshiftRight times */ + psrlw mm2, mm5 /* shift right each pixel NshiftRight times */ + pmullw mm1, mm3 /* mult 4 low words of Src and Kernel */ + pmullw mm2, mm4 /* mult 4 high words of Src and Kernel */ + paddsw mm1, mm2 /* add 4 words of the high and low bytes */ + paddsw mm7, mm1 /* add MM1 to accumulator MM7 */ + movq mm1, [esi] /* load 8 bytes of the Src */ + dec esi + add esi, eax /* move Src pointer 1 row below */ + movq mm3, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + punpcklbw mm1, mm0 /* unpack first 4 bytes into words */ + psrlw mm1, mm5 /* shift right each pixel NshiftRight times */ + pmullw mm1, mm3 /* mult 4 low words of Src and Kernel */ + paddsw mm7, mm1 /* add MM1 to accumulator MM7 */ + /* --- 2 */ + movq mm1, [esi] /* load 8 bytes of the Src */ + movq mm2, mm1 /* copy MM1 into MM2 */ + inc esi /* move pointer to the next 8 bytes of Src */ + movq mm3, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + movq mm4, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + punpcklbw mm1, mm0 /* unpack first 4 bytes into words */ + punpckhbw mm2, mm0 /* unpack second 4 bytes into words */ + psrlw mm1, mm5 /* shift right each pixel NshiftRight times */ + psrlw mm2, mm5 /* shift right each pixel NshiftRight times */ + pmullw mm1, mm3 /* mult 4 low words of Src and Kernel */ + pmullw mm2, mm4 /* mult 4 high words of Src and Kernel */ + paddsw mm1, mm2 /* add 4 words of the high and low bytes */ + paddsw mm7, mm1 /* add MM1 to accumulator MM7 */ + movq mm1, [esi] /* load 8 bytes of the Src */ + dec esi + add esi, eax /* move Src pointer 1 row below */ + movq mm3, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + punpcklbw mm1, mm0 /* unpack first 4 bytes into words */ + psrlw mm1, mm5 /* shift right each pixel NshiftRight times */ + pmullw mm1, mm3 /* mult 4 low words of Src and Kernel */ + paddsw mm7, mm1 /* add MM1 to accumulator MM7 */ + /* --- 3 */ + movq mm1, [esi] /* load 8 bytes of the Src */ + movq mm2, mm1 /* copy MM1 into MM2 */ + inc esi /* move pointer to the next 8 bytes of Src */ + movq mm3, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + movq mm4, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + punpcklbw mm1, mm0 /* unpack first 4 bytes into words */ + punpckhbw mm2, mm0 /* unpack second 4 bytes into words */ + psrlw mm1, mm5 /* shift right each pixel NshiftRight times */ + psrlw mm2, mm5 /* shift right each pixel NshiftRight times */ + pmullw mm1, mm3 /* mult 4 low words of Src and Kernel */ + pmullw mm2, mm4 /* mult 4 high words of Src and Kernel */ + paddsw mm1, mm2 /* add 4 words of the high and low bytes */ + paddsw mm7, mm1 /* add MM1 to accumulator MM7 */ + movq mm1, [esi] /* load 8 bytes of the Src */ + dec esi + add esi, eax /* move Src pointer 1 row below */ + movq mm3, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + punpcklbw mm1, mm0 /* unpack first 4 bytes into words */ + psrlw mm1, mm5 /* shift right each pixel NshiftRight times */ + pmullw mm1, mm3 /* mult 4 low words of Src and Kernel */ + paddsw mm7, mm1 /* add MM1 to accumulator MM7 */ + /* --- 4 */ + movq mm1, [esi] /* load 8 bytes of the Src */ + movq mm2, mm1 /* copy MM1 into MM2 */ + inc esi /* move pointer to the next 8 bytes of Src */ + movq mm3, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + movq mm4, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + punpcklbw mm1, mm0 /* unpack first 4 bytes into words */ + punpckhbw mm2, mm0 /* unpack second 4 bytes into words */ + psrlw mm1, mm5 /* shift right each pixel NshiftRight times */ + psrlw mm2, mm5 /* shift right each pixel NshiftRight times */ + pmullw mm1, mm3 /* mult 4 low words of Src and Kernel */ + pmullw mm2, mm4 /* mult 4 high words of Src and Kernel */ + paddsw mm1, mm2 /* add 4 words of the high and low bytes */ + paddsw mm7, mm1 /* add MM1 to accumulator MM7 */ + movq mm1, [esi] /* load 8 bytes of the Src */ + dec esi + add esi, eax /* move Src pointer 1 row below */ + movq mm3, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + punpcklbw mm1, mm0 /* unpack first 4 bytes into words */ + psrlw mm1, mm5 /* shift right each pixel NshiftRight times */ + pmullw mm1, mm3 /* mult 4 low words of Src and Kernel */ + paddsw mm7, mm1 /* add MM1 to accumulator MM7 */ + /* --- 5 */ + movq mm1, [esi] /* load 8 bytes of the Src */ + movq mm2, mm1 /* copy MM1 into MM2 */ + inc esi /* move pointer to the next 8 bytes of Src */ + movq mm3, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + movq mm4, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + punpcklbw mm1, mm0 /* unpack first 4 bytes into words */ + punpckhbw mm2, mm0 /* unpack second 4 bytes into words */ + psrlw mm1, mm5 /* shift right each pixel NshiftRight times */ + psrlw mm2, mm5 /* shift right each pixel NshiftRight times */ + pmullw mm1, mm3 /* mult 4 low words of Src and Kernel */ + pmullw mm2, mm4 /* mult 4 high words of Src and Kernel */ + paddsw mm1, mm2 /* add 4 words of the high and low bytes */ + paddsw mm7, mm1 /* add MM1 to accumulator MM7 */ + movq mm1, [esi] /* load 8 bytes of the Src */ + dec esi + add esi, eax /* move Src pointer 1 row below */ + movq mm3, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + punpcklbw mm1, mm0 /* unpack first 4 bytes into words */ + psrlw mm1, mm5 /* shift right each pixel NshiftRight times */ + pmullw mm1, mm3 /* mult 4 low words of Src and Kernel */ + paddsw mm7, mm1 /* add MM1 to accumulator MM7 */ + /* --- 6 */ + movq mm1, [esi] /* load 8 bytes of the Src */ + movq mm2, mm1 /* copy MM1 into MM2 */ + inc esi /* move pointer to the next 8 bytes of Src */ + movq mm3, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + movq mm4, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + punpcklbw mm1, mm0 /* unpack first 4 bytes into words */ + punpckhbw mm2, mm0 /* unpack second 4 bytes into words */ + psrlw mm1, mm5 /* shift right each pixel NshiftRight times */ + psrlw mm2, mm5 /* shift right each pixel NshiftRight times */ + pmullw mm1, mm3 /* mult 4 low words of Src and Kernel */ + pmullw mm2, mm4 /* mult 4 high words of Src and Kernel */ + paddsw mm1, mm2 /* add 4 words of the high and low bytes */ + paddsw mm7, mm1 /* add MM1 to accumulator MM7 */ + movq mm1, [esi] /* load 8 bytes of the Src */ + dec esi + add esi, eax /* move Src pointer 1 row below */ + movq mm3, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + punpcklbw mm1, mm0 /* unpack first 4 bytes into words */ + psrlw mm1, mm5 /* shift right each pixel NshiftRight times */ + pmullw mm1, mm3 /* mult 4 low words of Src and Kernel */ + paddsw mm7, mm1 /* add MM1 to accumulator MM7 */ + /* --- 7 */ + movq mm1, [esi] /* load 8 bytes of the Src */ + movq mm2, mm1 /* copy MM1 into MM2 */ + inc esi /* move pointer to the next 8 bytes of Src */ + movq mm3, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + movq mm4, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + punpcklbw mm1, mm0 /* unpack first 4 bytes into words */ + punpckhbw mm2, mm0 /* unpack second 4 bytes into words */ + psrlw mm1, mm5 /* shift right each pixel NshiftRight times */ + psrlw mm2, mm5 /* shift right each pixel NshiftRight times */ + pmullw mm1, mm3 /* mult 4 low words of Src and Kernel */ + pmullw mm2, mm4 /* mult 4 high words of Src and Kernel */ + paddsw mm1, mm2 /* add 4 words of the high and low bytes */ + paddsw mm7, mm1 /* add MM1 to accumulator MM7 */ + movq mm1, [esi] /* load 8 bytes of the Src */ + dec esi + add esi, eax /* move Src pointer 1 row below */ + movq mm3, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + punpcklbw mm1, mm0 /* unpack first 4 bytes into words */ + psrlw mm1, mm5 /* shift right each pixel NshiftRight times */ + pmullw mm1, mm3 /* mult 4 low words of Src and Kernel */ + paddsw mm7, mm1 /* add MM1 to accumulator MM7 */ + /* --- 8 */ + movq mm1, [esi] /* load 8 bytes of the Src */ + movq mm2, mm1 /* copy MM1 into MM2 */ + inc esi /* move pointer to the next 8 bytes of Src */ + movq mm3, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + movq mm4, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + punpcklbw mm1, mm0 /* unpack first 4 bytes into words */ + punpckhbw mm2, mm0 /* unpack second 4 bytes into words */ + psrlw mm1, mm5 /* shift right each pixel NshiftRight times */ + psrlw mm2, mm5 /* shift right each pixel NshiftRight times */ + pmullw mm1, mm3 /* mult 4 low words of Src and Kernel */ + pmullw mm2, mm4 /* mult 4 high words of Src and Kernel */ + paddsw mm1, mm2 /* add 4 words of the high and low bytes */ + paddsw mm7, mm1 /* add MM1 to accumulator MM7 */ + movq mm1, [esi] /* load 8 bytes of the Src */ + dec esi + add esi, eax /* move Src pointer 1 row below */ + movq mm3, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + punpcklbw mm1, mm0 /* unpack first 4 bytes into words */ + psrlw mm1, mm5 /* shift right each pixel NshiftRight times */ + pmullw mm1, mm3 /* mult 4 low words of Src and Kernel */ + paddsw mm7, mm1 /* add MM1 to accumulator MM7 */ + /* --- 9 */ + movq mm1, [esi] /* load 8 bytes of the Src */ + movq mm2, mm1 /* copy MM1 into MM2 */ + inc esi /* move pointer to the next 8 bytes of Src */ + movq mm3, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + movq mm4, [edx] /* load 4 words of Kernel */ + add edx, 8 /* move pointer to other 4 words */ + punpcklbw mm1, mm0 /* unpack first 4 bytes into words */ + punpckhbw mm2, mm0 /* unpack second 4 bytes into words */ + psrlw mm1, mm5 /* shift right each pixel NshiftRight times */ + psrlw mm2, mm5 /* shift right each pixel NshiftRight times */ + pmullw mm1, mm3 /* mult 4 low words of Src and Kernel */ + pmullw mm2, mm4 /* mult 4 high words of Src and Kernel */ + paddsw mm1, mm2 /* add 4 words of the high and low bytes */ + paddsw mm7, mm1 /* add MM1 to accumulator MM7 */ + movq mm1, [esi] /* load 8 bytes of the Src */ + movq mm3, [edx] /* load 4 words of Kernel */ + punpcklbw mm1, mm0 /* unpack first 4 bytes into words */ + psrlw mm1, mm5 /* shift right each pixel NshiftRight times */ + pmullw mm1, mm3 /* mult 4 low words of Src and Kernel */ + paddsw mm7, mm1 /* add MM1 to accumulator MM7 */ + /* ---, */ + movq mm3, mm7 /* copy MM7 into MM3 */ + psrlq mm7, 32 /* shift 2 left words to the right */ + paddsw mm7, mm3 /* add 2 left and 2 right result words */ + movq mm2, mm7 /* copy MM7 into MM2 */ + psrlq mm7, 16 /* shift 1 left word to the right */ + paddsw mm7, mm2 /* add 1 left and 1 right result words */ + movd mm1, eax /* save EAX in MM1 */ + packuswb mm7, mm0 /* pack division result with saturation */ + movd eax, mm7 /* copy saturated result into EAX */ + mov [edi], al /* copy a byte result into Dest */ + movd eax, mm1 /* restore saved EAX */ + /* --, */ + movd esi, mm6 /* move Src pointer to the top pixel */ + sub edx, 208 /* EDX = Kernel address */ + inc esi /* move Src pointer to the next pixel */ + inc edi /* move Dest pointer to the next pixel */ + /* ---, */ + dec ecx /* decrease loop counter COLUMNS */ + jnz L10392 /* check loop termination, proceed if required */ + add esi, 8 /* move to the next row in Src */ + add edi, 8 /* move to the next row in Dest */ + dec ebx /* decrease loop counter ROWS */ + jnz L10390 /* check loop termination, proceed if required */ + /* ---, */ + emms /* exit MMX state */ + popa + } +#else + asm volatile + ("pusha \n\t" "pxor %%mm0, %%mm0 \n\t" /* zero MM0 */ + "xor %%ebx, %%ebx \n\t" /* zero EBX */ + "mov %5, %%bl \n\t" /* load NRightShift into BL */ + "movd %%ebx, %%mm5 \n\t" /* copy NRightShift into MM5 */ + "mov %4, %%edx \n\t" /* load Kernel address into EDX */ + "mov %1, %%esi \n\t" /* load Src address to ESI */ + "mov %0, %%edi \n\t" /* load Dest address to EDI */ + "add $4, %%edi \n\t" /* 4 column offset from the left edge */ + "mov %3, %%eax \n\t" /* load columns into EAX */ + "add %%eax, %%edi \n\t" /* 4 row offset from the top edge */ + "add %%eax, %%edi \n\t" "add %%eax, %%edi \n\t" "add %%eax, %%edi \n\t" "mov %2, %%ebx \n\t" /* initialize ROWS counter */ + "sub $8, %%ebx \n\t" /* do not use first 4 and last 4 rows */ + /* --- */ + ".L10390: \n\t" "mov %%eax, %%ecx \n\t" /* initialize COLUMNS counter */ + "sub $8, %%ecx \n\t" /* do not use first 4 and last 4 columns */ + ".align 16 \n\t" /* 16 byte alignment of the loop entry */ + ".L10392: \n\t" "pxor %%mm7, %%mm7 \n\t" /* zero MM7 (accumulator) */ + "movd %%esi, %%mm6 \n\t" /* save ESI in MM6 */ + /* --- 1 */ + "movq (%%esi), %%mm1 \n\t" /* load 8 bytes of the Src */ + "movq %%mm1, %%mm2 \n\t" /* copy MM1 into MM2 */ + "inc %%esi \n\t" /* move pointer to the next 8 bytes of Src */ + "movq (%%edx), %%mm3 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "movq (%%edx), %%mm4 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "punpcklbw %%mm0, %%mm1 \n\t" /* unpack first 4 bytes into words */ + "punpckhbw %%mm0, %%mm2 \n\t" /* unpack second 4 bytes into words */ + "psrlw %%mm5, %%mm1 \n\t" /* shift right each pixel NshiftRight times */ + "psrlw %%mm5, %%mm2 \n\t" /* shift right each pixel NshiftRight times */ + "pmullw %%mm3, %%mm1 \n\t" /* mult. 4 low words of Src and Kernel */ + "pmullw %%mm4, %%mm2 \n\t" /* mult. 4 high words of Src and Kernel */ + "paddsw %%mm2, %%mm1 \n\t" /* add 4 words of the high and low bytes */ + "paddsw %%mm1, %%mm7 \n\t" /* add MM1 to accumulator MM7 */ + "movq (%%esi), %%mm1 \n\t" /* load 8 bytes of the Src */ + "dec %%esi \n\t" "add %%eax, %%esi \n\t" /* move Src pointer 1 row below */ + "movq (%%edx), %%mm3 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "punpcklbw %%mm0, %%mm1 \n\t" /* unpack first 4 bytes into words */ + "psrlw %%mm5, %%mm1 \n\t" /* shift right each pixel NshiftRight times */ + "pmullw %%mm3, %%mm1 \n\t" /* mult. 4 low words of Src and Kernel */ + "paddsw %%mm1, %%mm7 \n\t" /* add MM1 to accumulator MM7 */ + /* --- 2 */ + "movq (%%esi), %%mm1 \n\t" /* load 8 bytes of the Src */ + "movq %%mm1, %%mm2 \n\t" /* copy MM1 into MM2 */ + "inc %%esi \n\t" /* move pointer to the next 8 bytes of Src */ + "movq (%%edx), %%mm3 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "movq (%%edx), %%mm4 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "punpcklbw %%mm0, %%mm1 \n\t" /* unpack first 4 bytes into words */ + "punpckhbw %%mm0, %%mm2 \n\t" /* unpack second 4 bytes into words */ + "psrlw %%mm5, %%mm1 \n\t" /* shift right each pixel NshiftRight times */ + "psrlw %%mm5, %%mm2 \n\t" /* shift right each pixel NshiftRight times */ + "pmullw %%mm3, %%mm1 \n\t" /* mult. 4 low words of Src and Kernel */ + "pmullw %%mm4, %%mm2 \n\t" /* mult. 4 high words of Src and Kernel */ + "paddsw %%mm2, %%mm1 \n\t" /* add 4 words of the high and low bytes */ + "paddsw %%mm1, %%mm7 \n\t" /* add MM1 to accumulator MM7 */ + "movq (%%esi), %%mm1 \n\t" /* load 8 bytes of the Src */ + "dec %%esi \n\t" "add %%eax, %%esi \n\t" /* move Src pointer 1 row below */ + "movq (%%edx), %%mm3 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "punpcklbw %%mm0, %%mm1 \n\t" /* unpack first 4 bytes into words */ + "psrlw %%mm5, %%mm1 \n\t" /* shift right each pixel NshiftRight times */ + "pmullw %%mm3, %%mm1 \n\t" /* mult. 4 low words of Src and Kernel */ + "paddsw %%mm1, %%mm7 \n\t" /* add MM1 to accumulator MM7 */ + /* --- 3 */ + "movq (%%esi), %%mm1 \n\t" /* load 8 bytes of the Src */ + "movq %%mm1, %%mm2 \n\t" /* copy MM1 into MM2 */ + "inc %%esi \n\t" /* move pointer to the next 8 bytes of Src */ + "movq (%%edx), %%mm3 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "movq (%%edx), %%mm4 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "punpcklbw %%mm0, %%mm1 \n\t" /* unpack first 4 bytes into words */ + "punpckhbw %%mm0, %%mm2 \n\t" /* unpack second 4 bytes into words */ + "psrlw %%mm5, %%mm1 \n\t" /* shift right each pixel NshiftRight times */ + "psrlw %%mm5, %%mm2 \n\t" /* shift right each pixel NshiftRight times */ + "pmullw %%mm3, %%mm1 \n\t" /* mult. 4 low words of Src and Kernel */ + "pmullw %%mm4, %%mm2 \n\t" /* mult. 4 high words of Src and Kernel */ + "paddsw %%mm2, %%mm1 \n\t" /* add 4 words of the high and low bytes */ + "paddsw %%mm1, %%mm7 \n\t" /* add MM1 to accumulator MM7 */ + "movq (%%esi), %%mm1 \n\t" /* load 8 bytes of the Src */ + "dec %%esi \n\t" "add %%eax, %%esi \n\t" /* move Src pointer 1 row below */ + "movq (%%edx), %%mm3 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "punpcklbw %%mm0, %%mm1 \n\t" /* unpack first 4 bytes into words */ + "psrlw %%mm5, %%mm1 \n\t" /* shift right each pixel NshiftRight times */ + "pmullw %%mm3, %%mm1 \n\t" /* mult. 4 low words of Src and Kernel */ + "paddsw %%mm1, %%mm7 \n\t" /* add MM1 to accumulator MM7 */ + /* --- 4 */ + "movq (%%esi), %%mm1 \n\t" /* load 8 bytes of the Src */ + "movq %%mm1, %%mm2 \n\t" /* copy MM1 into MM2 */ + "inc %%esi \n\t" /* move pointer to the next 8 bytes of Src */ + "movq (%%edx), %%mm3 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "movq (%%edx), %%mm4 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "punpcklbw %%mm0, %%mm1 \n\t" /* unpack first 4 bytes into words */ + "punpckhbw %%mm0, %%mm2 \n\t" /* unpack second 4 bytes into words */ + "psrlw %%mm5, %%mm1 \n\t" /* shift right each pixel NshiftRight times */ + "psrlw %%mm5, %%mm2 \n\t" /* shift right each pixel NshiftRight times */ + "pmullw %%mm3, %%mm1 \n\t" /* mult. 4 low words of Src and Kernel */ + "pmullw %%mm4, %%mm2 \n\t" /* mult. 4 high words of Src and Kernel */ + "paddsw %%mm2, %%mm1 \n\t" /* add 4 words of the high and low bytes */ + "paddsw %%mm1, %%mm7 \n\t" /* add MM1 to accumulator MM7 */ + "movq (%%esi), %%mm1 \n\t" /* load 8 bytes of the Src */ + "dec %%esi \n\t" "add %%eax, %%esi \n\t" /* move Src pointer 1 row below */ + "movq (%%edx), %%mm3 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "punpcklbw %%mm0, %%mm1 \n\t" /* unpack first 4 bytes into words */ + "psrlw %%mm5, %%mm1 \n\t" /* shift right each pixel NshiftRight times */ + "pmullw %%mm3, %%mm1 \n\t" /* mult. 4 low words of Src and Kernel */ + "paddsw %%mm1, %%mm7 \n\t" /* add MM1 to accumulator MM7 */ + /* --- 5 */ + "movq (%%esi), %%mm1 \n\t" /* load 8 bytes of the Src */ + "movq %%mm1, %%mm2 \n\t" /* copy MM1 into MM2 */ + "inc %%esi \n\t" /* move pointer to the next 8 bytes of Src */ + "movq (%%edx), %%mm3 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "movq (%%edx), %%mm4 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "punpcklbw %%mm0, %%mm1 \n\t" /* unpack first 4 bytes into words */ + "punpckhbw %%mm0, %%mm2 \n\t" /* unpack second 4 bytes into words */ + "psrlw %%mm5, %%mm1 \n\t" /* shift right each pixel NshiftRight times */ + "psrlw %%mm5, %%mm2 \n\t" /* shift right each pixel NshiftRight times */ + "pmullw %%mm3, %%mm1 \n\t" /* mult. 4 low words of Src and Kernel */ + "pmullw %%mm4, %%mm2 \n\t" /* mult. 4 high words of Src and Kernel */ + "paddsw %%mm2, %%mm1 \n\t" /* add 4 words of the high and low bytes */ + "paddsw %%mm1, %%mm7 \n\t" /* add MM1 to accumulator MM7 */ + "movq (%%esi), %%mm1 \n\t" /* load 8 bytes of the Src */ + "dec %%esi \n\t" "add %%eax, %%esi \n\t" /* move Src pointer 1 row below */ + "movq (%%edx), %%mm3 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "punpcklbw %%mm0, %%mm1 \n\t" /* unpack first 4 bytes into words */ + "psrlw %%mm5, %%mm1 \n\t" /* shift right each pixel NshiftRight times */ + "pmullw %%mm3, %%mm1 \n\t" /* mult. 4 low words of Src and Kernel */ + "paddsw %%mm1, %%mm7 \n\t" /* add MM1 to accumulator MM7 */ + /* --- 6 */ + "movq (%%esi), %%mm1 \n\t" /* load 8 bytes of the Src */ + "movq %%mm1, %%mm2 \n\t" /* copy MM1 into MM2 */ + "inc %%esi \n\t" /* move pointer to the next 8 bytes of Src */ + "movq (%%edx), %%mm3 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "movq (%%edx), %%mm4 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "punpcklbw %%mm0, %%mm1 \n\t" /* unpack first 4 bytes into words */ + "punpckhbw %%mm0, %%mm2 \n\t" /* unpack second 4 bytes into words */ + "psrlw %%mm5, %%mm1 \n\t" /* shift right each pixel NshiftRight times */ + "psrlw %%mm5, %%mm2 \n\t" /* shift right each pixel NshiftRight times */ + "pmullw %%mm3, %%mm1 \n\t" /* mult. 4 low words of Src and Kernel */ + "pmullw %%mm4, %%mm2 \n\t" /* mult. 4 high words of Src and Kernel */ + "paddsw %%mm2, %%mm1 \n\t" /* add 4 words of the high and low bytes */ + "paddsw %%mm1, %%mm7 \n\t" /* add MM1 to accumulator MM7 */ + "movq (%%esi), %%mm1 \n\t" /* load 8 bytes of the Src */ + "dec %%esi \n\t" "add %%eax, %%esi \n\t" /* move Src pointer 1 row below */ + "movq (%%edx), %%mm3 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "punpcklbw %%mm0, %%mm1 \n\t" /* unpack first 4 bytes into words */ + "psrlw %%mm5, %%mm1 \n\t" /* shift right each pixel NshiftRight times */ + "pmullw %%mm3, %%mm1 \n\t" /* mult. 4 low words of Src and Kernel */ + "paddsw %%mm1, %%mm7 \n\t" /* add MM1 to accumulator MM7 */ + /* --- 7 */ + "movq (%%esi), %%mm1 \n\t" /* load 8 bytes of the Src */ + "movq %%mm1, %%mm2 \n\t" /* copy MM1 into MM2 */ + "inc %%esi \n\t" /* move pointer to the next 8 bytes of Src */ + "movq (%%edx), %%mm3 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "movq (%%edx), %%mm4 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "punpcklbw %%mm0, %%mm1 \n\t" /* unpack first 4 bytes into words */ + "punpckhbw %%mm0, %%mm2 \n\t" /* unpack second 4 bytes into words */ + "psrlw %%mm5, %%mm1 \n\t" /* shift right each pixel NshiftRight times */ + "psrlw %%mm5, %%mm2 \n\t" /* shift right each pixel NshiftRight times */ + "pmullw %%mm3, %%mm1 \n\t" /* mult. 4 low words of Src and Kernel */ + "pmullw %%mm4, %%mm2 \n\t" /* mult. 4 high words of Src and Kernel */ + "paddsw %%mm2, %%mm1 \n\t" /* add 4 words of the high and low bytes */ + "paddsw %%mm1, %%mm7 \n\t" /* add MM1 to accumulator MM7 */ + "movq (%%esi), %%mm1 \n\t" /* load 8 bytes of the Src */ + "dec %%esi \n\t" "add %%eax, %%esi \n\t" /* move Src pointer 1 row below */ + "movq (%%edx), %%mm3 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "punpcklbw %%mm0, %%mm1 \n\t" /* unpack first 4 bytes into words */ + "psrlw %%mm5, %%mm1 \n\t" /* shift right each pixel NshiftRight times */ + "pmullw %%mm3, %%mm1 \n\t" /* mult. 4 low words of Src and Kernel */ + "paddsw %%mm1, %%mm7 \n\t" /* add MM1 to accumulator MM7 */ + /* --- 8 */ + "movq (%%esi), %%mm1 \n\t" /* load 8 bytes of the Src */ + "movq %%mm1, %%mm2 \n\t" /* copy MM1 into MM2 */ + "inc %%esi \n\t" /* move pointer to the next 8 bytes of Src */ + "movq (%%edx), %%mm3 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "movq (%%edx), %%mm4 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "punpcklbw %%mm0, %%mm1 \n\t" /* unpack first 4 bytes into words */ + "punpckhbw %%mm0, %%mm2 \n\t" /* unpack second 4 bytes into words */ + "psrlw %%mm5, %%mm1 \n\t" /* shift right each pixel NshiftRight times */ + "psrlw %%mm5, %%mm2 \n\t" /* shift right each pixel NshiftRight times */ + "pmullw %%mm3, %%mm1 \n\t" /* mult. 4 low words of Src and Kernel */ + "pmullw %%mm4, %%mm2 \n\t" /* mult. 4 high words of Src and Kernel */ + "paddsw %%mm2, %%mm1 \n\t" /* add 4 words of the high and low bytes */ + "paddsw %%mm1, %%mm7 \n\t" /* add MM1 to accumulator MM7 */ + "movq (%%esi), %%mm1 \n\t" /* load 8 bytes of the Src */ + "dec %%esi \n\t" "add %%eax, %%esi \n\t" /* move Src pointer 1 row below */ + "movq (%%edx), %%mm3 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "punpcklbw %%mm0, %%mm1 \n\t" /* unpack first 4 bytes into words */ + "psrlw %%mm5, %%mm1 \n\t" /* shift right each pixel NshiftRight times */ + "pmullw %%mm3, %%mm1 \n\t" /* mult. 4 low words of Src and Kernel */ + "paddsw %%mm1, %%mm7 \n\t" /* add MM1 to accumulator MM7 */ + /* --- 9 */ + "movq (%%esi), %%mm1 \n\t" /* load 8 bytes of the Src */ + "movq %%mm1, %%mm2 \n\t" /* copy MM1 into MM2 */ + "inc %%esi \n\t" /* move pointer to the next 8 bytes of Src */ + "movq (%%edx), %%mm3 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "movq (%%edx), %%mm4 \n\t" /* load 4 words of Kernel */ + "add $8, %%edx \n\t" /* move pointer to other 4 words */ + "punpcklbw %%mm0, %%mm1 \n\t" /* unpack first 4 bytes into words */ + "punpckhbw %%mm0, %%mm2 \n\t" /* unpack second 4 bytes into words */ + "psrlw %%mm5, %%mm1 \n\t" /* shift right each pixel NshiftRight times */ + "psrlw %%mm5, %%mm2 \n\t" /* shift right each pixel NshiftRight times */ + "pmullw %%mm3, %%mm1 \n\t" /* mult. 4 low words of Src and Kernel */ + "pmullw %%mm4, %%mm2 \n\t" /* mult. 4 high words of Src and Kernel */ + "paddsw %%mm2, %%mm1 \n\t" /* add 4 words of the high and low bytes */ + "paddsw %%mm1, %%mm7 \n\t" /* add MM1 to accumulator MM7 */ + "movq (%%esi), %%mm1 \n\t" /* load 8 bytes of the Src */ + "movq (%%edx), %%mm3 \n\t" /* load 4 words of Kernel */ + "punpcklbw %%mm0, %%mm1 \n\t" /* unpack first 4 bytes into words */ + "psrlw %%mm5, %%mm1 \n\t" /* shift right each pixel NshiftRight times */ + "pmullw %%mm3, %%mm1 \n\t" /* mult. 4 low words of Src and Kernel */ + "paddsw %%mm1, %%mm7 \n\t" /* add MM1 to accumulator MM7 */ + /* --- */ + "movq %%mm7, %%mm3 \n\t" /* copy MM7 into MM3 */ + "psrlq $32, %%mm7 \n\t" /* shift 2 left words to the right */ + "paddsw %%mm3, %%mm7 \n\t" /* add 2 left and 2 right result words */ + "movq %%mm7, %%mm2 \n\t" /* copy MM7 into MM2 */ + "psrlq $16, %%mm7 \n\t" /* shift 1 left word to the right */ + "paddsw %%mm2, %%mm7 \n\t" /* add 1 left and 1 right result words */ + "movd %%eax, %%mm1 \n\t" /* save EAX in MM1 */ + "packuswb %%mm0, %%mm7 \n\t" /* pack division result with saturation */ + "movd %%mm7, %%eax \n\t" /* copy saturated result into EAX */ + "mov %%al, (%%edi) \n\t" /* copy a byte result into Dest */ + "movd %%mm1, %%eax \n\t" /* restore saved EAX */ + /* -- */ + "movd %%mm6, %%esi \n\t" /* move Src pointer to the top pixel */ + "sub $208, %%edx \n\t" /* EDX = Kernel address */ + "inc %%esi \n\t" /* move Src pointer to the next pixel */ + "inc %%edi \n\t" /* move Dest pointer to the next pixel */ + /* --- */ + "dec %%ecx \n\t" /* decrease loop counter COLUMNS */ + "jnz .L10392 \n\t" /* check loop termination, proceed if required */ + "add $8, %%esi \n\t" /* move to the next row in Src */ + "add $8, %%edi \n\t" /* move to the next row in Dest */ + "dec %%ebx \n\t" /* decrease loop counter ROWS */ + "jnz .L10390 \n\t" /* check loop termination, proceed if required */ + /* --- */ + "emms \n\t" /* exit MMX state */ + "popa \n\t":"=m" (Dest) /* %0 */ + :"m"(Src), /* %1 */ + "m"(rows), /* %2 */ + "m"(columns), /* %3 */ + "m"(Kernel), /* %4 */ + "m"(NRightShift) /* %5 */ + ); +#endif +#endif + return (0); + } else { + /* No non-MMX implementation yet */ + return (-1); + } +} + +/* ------------------------------------------------------------------------------------ */ + +/*! +\brief Filter using SobelX: Dij = saturation255( ... ) + +\param Src The source 2D byte array to sobel-filter. Should be different from destination. +\param Dest The destination 2D byte array to store the result in. Should be different from source. +\param rows Number of rows in source/destination array. Must be >2. +\param columns Number of columns in source/destination array. Must be >7. + +Note: Non-MMX implementation not available for this function. + +\return Returns 1 if filter was applied, 0 otherwise. +*/ +int SDL_imageFilterSobelX(unsigned char *Src, unsigned char *Dest, int rows, int columns) +{ + /* Validate input parameters */ + if ((Src == NULL) || (Dest == NULL)) + return(-1); + + if ((columns < 8) || (rows < 3)) + return (-1); + + if ((SDL_imageFilterMMXdetect())) { +#ifdef USE_MMX +#if !defined(GCC__) + __asm + { + pusha + pxor mm0, mm0 /* zero MM0 */ + mov eax, columns /* load columns into EAX */ + /* ---, */ + mov esi, Src /* ESI = Src row 0 address */ + mov edi, Dest /* load Dest address to EDI */ + add edi, eax /* EDI = EDI + columns */ + inc edi /* 1 byte offset from the left edge */ + mov edx, rows /* initialize ROWS counter */ + sub edx, 2 /* do not use first and last rows */ + /* ---, */ +L10400: + mov ecx, eax /* initialize COLUMS counter */ + shr ecx, 3 /* EBX/8 (MMX loads 8 bytes at a time) */ + mov ebx, esi /* save ESI in EBX */ + movd mm1, edi /* save EDI in MM1 */ + align 16 /* 16 byte alignment of the loop entry */ +L10402: + /* ---, */ + movq mm4, [esi] /* load 8 bytes from Src */ + movq mm5, mm4 /* save MM4 in MM5 */ + add esi, 2 /* move ESI pointer 2 bytes right */ + punpcklbw mm4, mm0 /* unpack 4 low bytes into words */ + punpckhbw mm5, mm0 /* unpack 4 high bytes into words */ + movq mm6, [esi] /* load 8 bytes from Src */ + movq mm7, mm6 /* save MM6 in MM7 */ + sub esi, 2 /* move ESI pointer back 2 bytes left */ + punpcklbw mm6, mm0 /* unpack 4 low bytes into words */ + punpckhbw mm7, mm0 /* unpack 4 high bytes into words */ + add esi, eax /* move to the next row of Src */ + movq mm2, [esi] /* load 8 bytes from Src */ + movq mm3, mm2 /* save MM2 in MM3 */ + add esi, 2 /* move ESI pointer 2 bytes right */ + punpcklbw mm2, mm0 /* unpack 4 low bytes into words */ + punpckhbw mm3, mm0 /* unpack 4 high bytes into words */ + paddw mm4, mm2 /* add 4 low bytes to accumolator MM4 */ + paddw mm5, mm3 /* add 4 high bytes to accumolator MM5 */ + paddw mm4, mm2 /* add 4 low bytes to accumolator MM4 */ + paddw mm5, mm3 /* add 4 high bytes to accumolator MM5 */ + movq mm2, [esi] /* load 8 bytes from Src */ + movq mm3, mm2 /* save MM2 in MM3 */ + sub esi, 2 /* move ESI pointer back 2 bytes left */ + punpcklbw mm2, mm0 /* unpack 4 low bytes into words */ + punpckhbw mm3, mm0 /* unpack 4 high bytes into words */ + paddw mm6, mm2 /* add 4 low bytes to accumolator MM6 */ + paddw mm7, mm3 /* add 4 high bytes to accumolator MM7 */ + paddw mm6, mm2 /* add 4 low bytes to accumolator MM6 */ + paddw mm7, mm3 /* add 4 high bytes to accumolator MM7 */ + add esi, eax /* move to the next row of Src */ + movq mm2, [esi] /* load 8 bytes from Src */ + movq mm3, mm2 /* save MM2 in MM3 */ + add esi, 2 /* move ESI pointer 2 bytes right */ + punpcklbw mm2, mm0 /* unpack 4 low bytes into words */ + punpckhbw mm3, mm0 /* unpack 4 high bytes into words */ + paddw mm4, mm2 /* add 4 low bytes to accumolator MM4 */ + paddw mm5, mm3 /* add 4 high bytes to accumolator MM5 */ + movq mm2, [esi] /* load 8 bytes from Src */ + movq mm3, mm2 /* save MM2 in MM3 */ + sub esi, 2 /* move ESI pointer back 2 bytes left */ + punpcklbw mm2, mm0 /* unpack 4 low bytes into words */ + punpckhbw mm3, mm0 /* unpack 4 high bytes into words */ + paddw mm6, mm2 /* add 4 low bytes to accumolator MM6 */ + paddw mm7, mm3 /* add 4 high bytes to accumolator MM7 */ + /* ---, */ + movq mm2, mm4 /* copy MM4 into MM2 */ + psrlq mm4, 32 /* shift 2 left words to the right */ + psubw mm4, mm2 /* MM4 = MM4 - MM2 */ + movq mm3, mm6 /* copy MM6 into MM3 */ + psrlq mm6, 32 /* shift 2 left words to the right */ + psubw mm6, mm3 /* MM6 = MM6 - MM3 */ + punpckldq mm4, mm6 /* combine 2 words of MM6 and 2 words of MM4 */ + movq mm2, mm5 /* copy MM6 into MM2 */ + psrlq mm5, 32 /* shift 2 left words to the right */ + psubw mm5, mm2 /* MM5 = MM5 - MM2 */ + movq mm3, mm7 /* copy MM7 into MM3 */ + psrlq mm7, 32 /* shift 2 left words to the right */ + psubw mm7, mm3 /* MM7 = MM7 - MM3 */ + punpckldq mm5, mm7 /* combine 2 words of MM7 and 2 words of MM5 */ + /* Take abs values of MM4 and MM5 */ + movq mm6, mm4 /* copy MM4 into MM6 */ + movq mm7, mm5 /* copy MM5 into MM7 */ + psraw mm6, 15 /* fill MM6 words with word sign bit */ + psraw mm7, 15 /* fill MM7 words with word sign bit */ + pxor mm4, mm6 /* take 1's compliment of only neg words */ + pxor mm5, mm7 /* take 1's compliment of only neg words */ + psubsw mm4, mm6 /* add 1 to only neg words, W-(-1) or W-0 */ + psubsw mm5, mm7 /* add 1 to only neg words, W-(-1) or W-0 */ + packuswb mm4, mm5 /* combine and pack/saturate MM5 and MM4 */ + movq [edi], mm4 /* store result in Dest */ + /* ---, */ + sub esi, eax /* move to the current top row in Src */ + sub esi, eax + add esi, 8 /* move Src pointer to the next 8 pixels */ + add edi, 8 /* move Dest pointer to the next 8 pixels */ + /* ---, */ + dec ecx /* decrease loop counter COLUMNS */ + jnz L10402 /* check loop termination, proceed if required */ + mov esi, ebx /* restore most left current row Src address */ + movd edi, mm1 /* restore most left current row Dest address */ + add esi, eax /* move to the next row in Src */ + add edi, eax /* move to the next row in Dest */ + dec edx /* decrease loop counter ROWS */ + jnz L10400 /* check loop termination, proceed if required */ + /* ---, */ + emms /* exit MMX state */ + popa + } +#else + asm volatile + ("pusha \n\t" "pxor %%mm0, %%mm0 \n\t" /* zero MM0 */ + "mov %3, %%eax \n\t" /* load columns into EAX */ + /* --- */ + "mov %1, %%esi \n\t" /* ESI = Src row 0 address */ + "mov %0, %%edi \n\t" /* load Dest address to EDI */ + "add %%eax, %%edi \n\t" /* EDI = EDI + columns */ + "inc %%edi \n\t" /* 1 byte offset from the left edge */ + "mov %2, %%edx \n\t" /* initialize ROWS counter */ + "sub $2, %%edx \n\t" /* do not use first and last rows */ + /* --- */ + ".L10400: \n\t" "mov %%eax, %%ecx \n\t" /* initialize COLUMS counter */ + "shr $3, %%ecx \n\t" /* EBX/8 (MMX loads 8 bytes at a time) */ + "mov %%esi, %%ebx \n\t" /* save ESI in EBX */ + "movd %%edi, %%mm1 \n\t" /* save EDI in MM1 */ + ".align 16 \n\t" /* 16 byte alignment of the loop entry */ + ".L10402: \n\t" + /* --- */ + "movq (%%esi), %%mm4 \n\t" /* load 8 bytes from Src */ + "movq %%mm4, %%mm5 \n\t" /* save MM4 in MM5 */ + "add $2, %%esi \n\t" /* move ESI pointer 2 bytes right */ + "punpcklbw %%mm0, %%mm4 \n\t" /* unpack 4 low bytes into words */ + "punpckhbw %%mm0, %%mm5 \n\t" /* unpack 4 high bytes into words */ + "movq (%%esi), %%mm6 \n\t" /* load 8 bytes from Src */ + "movq %%mm6, %%mm7 \n\t" /* save MM6 in MM7 */ + "sub $2, %%esi \n\t" /* move ESI pointer back 2 bytes left */ + "punpcklbw %%mm0, %%mm6 \n\t" /* unpack 4 low bytes into words */ + "punpckhbw %%mm0, %%mm7 \n\t" /* unpack 4 high bytes into words */ + "add %%eax, %%esi \n\t" /* move to the next row of Src */ + "movq (%%esi), %%mm2 \n\t" /* load 8 bytes from Src */ + "movq %%mm2, %%mm3 \n\t" /* save MM2 in MM3 */ + "add $2, %%esi \n\t" /* move ESI pointer 2 bytes right */ + "punpcklbw %%mm0, %%mm2 \n\t" /* unpack 4 low bytes into words */ + "punpckhbw %%mm0, %%mm3 \n\t" /* unpack 4 high bytes into words */ + "paddw %%mm2, %%mm4 \n\t" /* add 4 low bytes to accumolator MM4 */ + "paddw %%mm3, %%mm5 \n\t" /* add 4 high bytes to accumolator MM5 */ + "paddw %%mm2, %%mm4 \n\t" /* add 4 low bytes to accumolator MM4 */ + "paddw %%mm3, %%mm5 \n\t" /* add 4 high bytes to accumolator MM5 */ + "movq (%%esi), %%mm2 \n\t" /* load 8 bytes from Src */ + "movq %%mm2, %%mm3 \n\t" /* save MM2 in MM3 */ + "sub $2, %%esi \n\t" /* move ESI pointer back 2 bytes left */ + "punpcklbw %%mm0, %%mm2 \n\t" /* unpack 4 low bytes into words */ + "punpckhbw %%mm0, %%mm3 \n\t" /* unpack 4 high bytes into words */ + "paddw %%mm2, %%mm6 \n\t" /* add 4 low bytes to accumolator MM6 */ + "paddw %%mm3, %%mm7 \n\t" /* add 4 high bytes to accumolator MM7 */ + "paddw %%mm2, %%mm6 \n\t" /* add 4 low bytes to accumolator MM6 */ + "paddw %%mm3, %%mm7 \n\t" /* add 4 high bytes to accumolator MM7 */ + "add %%eax, %%esi \n\t" /* move to the next row of Src */ + "movq (%%esi), %%mm2 \n\t" /* load 8 bytes from Src */ + "movq %%mm2, %%mm3 \n\t" /* save MM2 in MM3 */ + "add $2, %%esi \n\t" /* move ESI pointer 2 bytes right */ + "punpcklbw %%mm0, %%mm2 \n\t" /* unpack 4 low bytes into words */ + "punpckhbw %%mm0, %%mm3 \n\t" /* unpack 4 high bytes into words */ + "paddw %%mm2, %%mm4 \n\t" /* add 4 low bytes to accumolator MM4 */ + "paddw %%mm3, %%mm5 \n\t" /* add 4 high bytes to accumolator MM5 */ + "movq (%%esi), %%mm2 \n\t" /* load 8 bytes from Src */ + "movq %%mm2, %%mm3 \n\t" /* save MM2 in MM3 */ + "sub $2, %%esi \n\t" /* move ESI pointer back 2 bytes left */ + "punpcklbw %%mm0, %%mm2 \n\t" /* unpack 4 low bytes into words */ + "punpckhbw %%mm0, %%mm3 \n\t" /* unpack 4 high bytes into words */ + "paddw %%mm2, %%mm6 \n\t" /* add 4 low bytes to accumolator MM6 */ + "paddw %%mm3, %%mm7 \n\t" /* add 4 high bytes to accumolator MM7 */ + /* --- */ + "movq %%mm4, %%mm2 \n\t" /* copy MM4 into MM2 */ + "psrlq $32, %%mm4 \n\t" /* shift 2 left words to the right */ + "psubw %%mm2, %%mm4 \n\t" /* MM4 = MM4 - MM2 */ + "movq %%mm6, %%mm3 \n\t" /* copy MM6 into MM3 */ + "psrlq $32, %%mm6 \n\t" /* shift 2 left words to the right */ + "psubw %%mm3, %%mm6 \n\t" /* MM6 = MM6 - MM3 */ + "punpckldq %%mm6, %%mm4 \n\t" /* combine 2 words of MM6 and 2 words of MM4 */ + "movq %%mm5, %%mm2 \n\t" /* copy MM6 into MM2 */ + "psrlq $32, %%mm5 \n\t" /* shift 2 left words to the right */ + "psubw %%mm2, %%mm5 \n\t" /* MM5 = MM5 - MM2 */ + "movq %%mm7, %%mm3 \n\t" /* copy MM7 into MM3 */ + "psrlq $32, %%mm7 \n\t" /* shift 2 left words to the right */ + "psubw %%mm3, %%mm7 \n\t" /* MM7 = MM7 - MM3 */ + "punpckldq %%mm7, %%mm5 \n\t" /* combine 2 words of MM7 and 2 words of MM5 */ + /* Take abs values of MM4 and MM5 */ + "movq %%mm4, %%mm6 \n\t" /* copy MM4 into MM6 */ + "movq %%mm5, %%mm7 \n\t" /* copy MM5 into MM7 */ + "psraw $15, %%mm6 \n\t" /* fill MM6 words with word sign bit */ + "psraw $15, %%mm7 \n\t" /* fill MM7 words with word sign bit */ + "pxor %%mm6, %%mm4 \n\t" /* take 1's compliment of only neg. words */ + "pxor %%mm7, %%mm5 \n\t" /* take 1's compliment of only neg. words */ + "psubsw %%mm6, %%mm4 \n\t" /* add 1 to only neg. words, W-(-1) or W-0 */ + "psubsw %%mm7, %%mm5 \n\t" /* add 1 to only neg. words, W-(-1) or W-0 */ + "packuswb %%mm5, %%mm4 \n\t" /* combine and pack/saturate MM5 and MM4 */ + "movq %%mm4, (%%edi) \n\t" /* store result in Dest */ + /* --- */ + "sub %%eax, %%esi \n\t" /* move to the current top row in Src */ + "sub %%eax, %%esi \n\t" "add $8, %%esi \n\t" /* move Src pointer to the next 8 pixels */ + "add $8, %%edi \n\t" /* move Dest pointer to the next 8 pixels */ + /* --- */ + "dec %%ecx \n\t" /* decrease loop counter COLUMNS */ + "jnz .L10402 \n\t" /* check loop termination, proceed if required */ + "mov %%ebx, %%esi \n\t" /* restore most left current row Src address */ + "movd %%mm1, %%edi \n\t" /* restore most left current row Dest address */ + "add %%eax, %%esi \n\t" /* move to the next row in Src */ + "add %%eax, %%edi \n\t" /* move to the next row in Dest */ + "dec %%edx \n\t" /* decrease loop counter ROWS */ + "jnz .L10400 \n\t" /* check loop termination, proceed if required */ + /* --- */ + "emms \n\t" /* exit MMX state */ + "popa \n\t":"=m" (Dest) /* %0 */ + :"m"(Src), /* %1 */ + "m"(rows), /* %2 */ + "m"(columns) /* %3 */ + ); +#endif +#endif + return (0); + } else { + /* No non-MMX implementation yet */ + return (-1); + } +} + +/*! +\brief Filter using SobelXShiftRight: Dij = saturation255( ... ) + +\param Src The source 2D byte array to sobel-filter. Should be different from destination. +\param Dest The destination 2D byte array to store the result in. Should be different from source. +\param rows Number of rows in source/destination array. Must be >2. +\param columns Number of columns in source/destination array. Must be >8. +\param NRightShift The number of right bit shifts to apply to the filter sum. Must be <7. + +Note: Non-MMX implementation not available for this function. + +\return Returns 1 if filter was applied, 0 otherwise. +*/ +int SDL_imageFilterSobelXShiftRight(unsigned char *Src, unsigned char *Dest, int rows, int columns, + unsigned char NRightShift) +{ + /* Validate input parameters */ + if ((Src == NULL) || (Dest == NULL)) + return(-1); + if ((columns < 8) || (rows < 3) || (NRightShift > 7)) + return (-1); + + if ((SDL_imageFilterMMXdetect())) { +#ifdef USE_MMX +#if !defined(GCC__) + __asm + { + pusha + pxor mm0, mm0 /* zero MM0 */ + mov eax, columns /* load columns into EAX */ + xor ebx, ebx /* zero EBX */ + mov bl, NRightShift /* load NRightShift into BL */ + movd mm1, ebx /* copy NRightShift into MM1 */ + /* ---, */ + mov esi, Src /* ESI = Src row 0 address */ + mov edi, Dest /* load Dest address to EDI */ + add edi, eax /* EDI = EDI + columns */ + inc edi /* 1 byte offset from the left edge */ + /* initialize ROWS counter */ + sub rows, 2 /* do not use first and last rows */ + /* ---, */ +L10410: + mov ecx, eax /* initialize COLUMS counter */ + shr ecx, 3 /* EBX/8 (MMX loads 8 bytes at a time) */ + mov ebx, esi /* save ESI in EBX */ + mov edx, edi /* save EDI in EDX */ + align 16 /* 16 byte alignment of the loop entry */ +L10412: + /* ---, */ + movq mm4, [esi] /* load 8 bytes from Src */ + movq mm5, mm4 /* save MM4 in MM5 */ + add esi, 2 /* move ESI pointer 2 bytes right */ + punpcklbw mm4, mm0 /* unpack 4 low bytes into words */ + punpckhbw mm5, mm0 /* unpack 4 high bytes into words */ + psrlw mm4, mm1 /* shift right each pixel NshiftRight times */ + psrlw mm5, mm1 /* shift right each pixel NshiftRight times */ + movq mm6, [esi] /* load 8 bytes from Src */ + movq mm7, mm6 /* save MM6 in MM7 */ + sub esi, 2 /* move ESI pointer back 2 bytes left */ + punpcklbw mm6, mm0 /* unpack 4 low bytes into words */ + punpckhbw mm7, mm0 /* unpack 4 high bytes into words */ + psrlw mm6, mm1 /* shift right each pixel NshiftRight times */ + psrlw mm7, mm1 /* shift right each pixel NshiftRight times */ + add esi, eax /* move to the next row of Src */ + movq mm2, [esi] /* load 8 bytes from Src */ + movq mm3, mm2 /* save MM2 in MM3 */ + add esi, 2 /* move ESI pointer 2 bytes right */ + punpcklbw mm2, mm0 /* unpack 4 low bytes into words */ + punpckhbw mm3, mm0 /* unpack 4 high bytes into words */ + psrlw mm2, mm1 /* shift right each pixel NshiftRight times */ + psrlw mm3, mm1 /* shift right each pixel NshiftRight times */ + paddw mm4, mm2 /* add 4 low bytes to accumolator MM4 */ + paddw mm5, mm3 /* add 4 high bytes to accumolator MM5 */ + paddw mm4, mm2 /* add 4 low bytes to accumolator MM4 */ + paddw mm5, mm3 /* add 4 high bytes to accumolator MM5 */ + movq mm2, [esi] /* load 8 bytes from Src */ + movq mm3, mm2 /* save MM2 in MM3 */ + sub esi, 2 /* move ESI pointer back 2 bytes left */ + punpcklbw mm2, mm0 /* unpack 4 low bytes into words */ + punpckhbw mm3, mm0 /* unpack 4 high bytes into words */ + psrlw mm2, mm1 /* shift right each pixel NshiftRight times */ + psrlw mm3, mm1 /* shift right each pixel NshiftRight times */ + paddw mm6, mm2 /* add 4 low bytes to accumolator MM6 */ + paddw mm7, mm3 /* add 4 high bytes to accumolator MM7 */ + paddw mm6, mm2 /* add 4 low bytes to accumolator MM6 */ + paddw mm7, mm3 /* add 4 high bytes to accumolator MM7 */ + add esi, eax /* move to the next row of Src */ + movq mm2, [esi] /* load 8 bytes from Src */ + movq mm3, mm2 /* save MM2 in MM3 */ + add esi, 2 /* move ESI pointer 2 bytes right */ + punpcklbw mm2, mm0 /* unpack 4 low bytes into words */ + punpckhbw mm3, mm0 /* unpack 4 high bytes into words */ + psrlw mm2, mm1 /* shift right each pixel NshiftRight times */ + psrlw mm3, mm1 /* shift right each pixel NshiftRight times */ + paddw mm4, mm2 /* add 4 low bytes to accumolator MM4 */ + paddw mm5, mm3 /* add 4 high bytes to accumolator MM5 */ + movq mm2, [esi] /* load 8 bytes from Src */ + movq mm3, mm2 /* save MM2 in MM3 */ + sub esi, 2 /* move ESI pointer back 2 bytes left */ + punpcklbw mm2, mm0 /* unpack 4 low bytes into words */ + punpckhbw mm3, mm0 /* unpack 4 high bytes into words */ + psrlw mm2, mm1 /* shift right each pixel NshiftRight times */ + psrlw mm3, mm1 /* shift right each pixel NshiftRight times */ + paddw mm6, mm2 /* add 4 low bytes to accumolator MM6 */ + paddw mm7, mm3 /* add 4 high bytes to accumolator MM7 */ + /* ---, */ + movq mm2, mm4 /* copy MM4 into MM2 */ + psrlq mm4, 32 /* shift 2 left words to the right */ + psubw mm4, mm2 /* MM4 = MM4 - MM2 */ + movq mm3, mm6 /* copy MM6 into MM3 */ + psrlq mm6, 32 /* shift 2 left words to the right */ + psubw mm6, mm3 /* MM6 = MM6 - MM3 */ + punpckldq mm4, mm6 /* combine 2 words of MM6 and 2 words of MM4 */ + movq mm2, mm5 /* copy MM6 into MM2 */ + psrlq mm5, 32 /* shift 2 left words to the right */ + psubw mm5, mm2 /* MM5 = MM5 - MM2 */ + movq mm3, mm7 /* copy MM7 into MM3 */ + psrlq mm7, 32 /* shift 2 left words to the right */ + psubw mm7, mm3 /* MM7 = MM7 - MM3 */ + punpckldq mm5, mm7 /* combine 2 words of MM7 and 2 words of MM5 */ + /* Take abs values of MM4 and MM5 */ + movq mm6, mm4 /* copy MM4 into MM6 */ + movq mm7, mm5 /* copy MM5 into MM7 */ + psraw mm6, 15 /* fill MM6 words with word sign bit */ + psraw mm7, 15 /* fill MM7 words with word sign bit */ + pxor mm4, mm6 /* take 1's compliment of only neg words */ + pxor mm5, mm7 /* take 1's compliment of only neg words */ + psubsw mm4, mm6 /* add 1 to only neg words, W-(-1) or W-0 */ + psubsw mm5, mm7 /* add 1 to only neg words, W-(-1) or W-0 */ + packuswb mm4, mm5 /* combine and pack/saturate MM5 and MM4 */ + movq [edi], mm4 /* store result in Dest */ + /* ---, */ + sub esi, eax /* move to the current top row in Src */ + sub esi, eax + add esi, 8 /* move Src pointer to the next 8 pixels */ + add edi, 8 /* move Dest pointer to the next 8 pixels */ + /* ---, */ + dec ecx /* decrease loop counter COLUMNS */ + jnz L10412 /* check loop termination, proceed if required */ + mov esi, ebx /* restore most left current row Src address */ + mov edi, edx /* restore most left current row Dest address */ + add esi, eax /* move to the next row in Src */ + add edi, eax /* move to the next row in Dest */ + dec rows /* decrease loop counter ROWS */ + jnz L10410 /* check loop termination, proceed if required */ + /* ---, */ + emms /* exit MMX state */ + popa + } +#else + asm volatile + ("pusha \n\t" "pxor %%mm0, %%mm0 \n\t" /* zero MM0 */ + "mov %3, %%eax \n\t" /* load columns into EAX */ + "xor %%ebx, %%ebx \n\t" /* zero EBX */ + "mov %4, %%bl \n\t" /* load NRightShift into BL */ + "movd %%ebx, %%mm1 \n\t" /* copy NRightShift into MM1 */ + /* --- */ + "mov %1, %%esi \n\t" /* ESI = Src row 0 address */ + "mov %0, %%edi \n\t" /* load Dest address to EDI */ + "add %%eax, %%edi \n\t" /* EDI = EDI + columns */ + "inc %%edi \n\t" /* 1 byte offset from the left edge */ + /* initialize ROWS counter */ + "subl $2, %2 \n\t" /* do not use first and last rows */ + /* --- */ + ".L10410: \n\t" "mov %%eax, %%ecx \n\t" /* initialize COLUMS counter */ + "shr $3, %%ecx \n\t" /* EBX/8 (MMX loads 8 bytes at a time) */ + "mov %%esi, %%ebx \n\t" /* save ESI in EBX */ + "mov %%edi, %%edx \n\t" /* save EDI in EDX */ + ".align 16 \n\t" /* 16 byte alignment of the loop entry */ + ".L10412: \n\t" + /* --- */ + "movq (%%esi), %%mm4 \n\t" /* load 8 bytes from Src */ + "movq %%mm4, %%mm5 \n\t" /* save MM4 in MM5 */ + "add $2, %%esi \n\t" /* move ESI pointer 2 bytes right */ + "punpcklbw %%mm0, %%mm4 \n\t" /* unpack 4 low bytes into words */ + "punpckhbw %%mm0, %%mm5 \n\t" /* unpack 4 high bytes into words */ + "psrlw %%mm1, %%mm4 \n\t" /* shift right each pixel NshiftRight times */ + "psrlw %%mm1, %%mm5 \n\t" /* shift right each pixel NshiftRight times */ + "movq (%%esi), %%mm6 \n\t" /* load 8 bytes from Src */ + "movq %%mm6, %%mm7 \n\t" /* save MM6 in MM7 */ + "sub $2, %%esi \n\t" /* move ESI pointer back 2 bytes left */ + "punpcklbw %%mm0, %%mm6 \n\t" /* unpack 4 low bytes into words */ + "punpckhbw %%mm0, %%mm7 \n\t" /* unpack 4 high bytes into words */ + "psrlw %%mm1, %%mm6 \n\t" /* shift right each pixel NshiftRight times */ + "psrlw %%mm1, %%mm7 \n\t" /* shift right each pixel NshiftRight times */ + "add %%eax, %%esi \n\t" /* move to the next row of Src */ + "movq (%%esi), %%mm2 \n\t" /* load 8 bytes from Src */ + "movq %%mm2, %%mm3 \n\t" /* save MM2 in MM3 */ + "add $2, %%esi \n\t" /* move ESI pointer 2 bytes right */ + "punpcklbw %%mm0, %%mm2 \n\t" /* unpack 4 low bytes into words */ + "punpckhbw %%mm0, %%mm3 \n\t" /* unpack 4 high bytes into words */ + "psrlw %%mm1, %%mm2 \n\t" /* shift right each pixel NshiftRight times */ + "psrlw %%mm1, %%mm3 \n\t" /* shift right each pixel NshiftRight times */ + "paddw %%mm2, %%mm4 \n\t" /* add 4 low bytes to accumolator MM4 */ + "paddw %%mm3, %%mm5 \n\t" /* add 4 high bytes to accumolator MM5 */ + "paddw %%mm2, %%mm4 \n\t" /* add 4 low bytes to accumolator MM4 */ + "paddw %%mm3, %%mm5 \n\t" /* add 4 high bytes to accumolator MM5 */ + "movq (%%esi), %%mm2 \n\t" /* load 8 bytes from Src */ + "movq %%mm2, %%mm3 \n\t" /* save MM2 in MM3 */ + "sub $2, %%esi \n\t" /* move ESI pointer back 2 bytes left */ + "punpcklbw %%mm0, %%mm2 \n\t" /* unpack 4 low bytes into words */ + "punpckhbw %%mm0, %%mm3 \n\t" /* unpack 4 high bytes into words */ + "psrlw %%mm1, %%mm2 \n\t" /* shift right each pixel NshiftRight times */ + "psrlw %%mm1, %%mm3 \n\t" /* shift right each pixel NshiftRight times */ + "paddw %%mm2, %%mm6 \n\t" /* add 4 low bytes to accumolator MM6 */ + "paddw %%mm3, %%mm7 \n\t" /* add 4 high bytes to accumolator MM7 */ + "paddw %%mm2, %%mm6 \n\t" /* add 4 low bytes to accumolator MM6 */ + "paddw %%mm3, %%mm7 \n\t" /* add 4 high bytes to accumolator MM7 */ + "add %%eax, %%esi \n\t" /* move to the next row of Src */ + "movq (%%esi), %%mm2 \n\t" /* load 8 bytes from Src */ + "movq %%mm2, %%mm3 \n\t" /* save MM2 in MM3 */ + "add $2, %%esi \n\t" /* move ESI pointer 2 bytes right */ + "punpcklbw %%mm0, %%mm2 \n\t" /* unpack 4 low bytes into words */ + "punpckhbw %%mm0, %%mm3 \n\t" /* unpack 4 high bytes into words */ + "psrlw %%mm1, %%mm2 \n\t" /* shift right each pixel NshiftRight times */ + "psrlw %%mm1, %%mm3 \n\t" /* shift right each pixel NshiftRight times */ + "paddw %%mm2, %%mm4 \n\t" /* add 4 low bytes to accumolator MM4 */ + "paddw %%mm3, %%mm5 \n\t" /* add 4 high bytes to accumolator MM5 */ + "movq (%%esi), %%mm2 \n\t" /* load 8 bytes from Src */ + "movq %%mm2, %%mm3 \n\t" /* save MM2 in MM3 */ + "sub $2, %%esi \n\t" /* move ESI pointer back 2 bytes left */ + "punpcklbw %%mm0, %%mm2 \n\t" /* unpack 4 low bytes into words */ + "punpckhbw %%mm0, %%mm3 \n\t" /* unpack 4 high bytes into words */ + "psrlw %%mm1, %%mm2 \n\t" /* shift right each pixel NshiftRight times */ + "psrlw %%mm1, %%mm3 \n\t" /* shift right each pixel NshiftRight times */ + "paddw %%mm2, %%mm6 \n\t" /* add 4 low bytes to accumolator MM6 */ + "paddw %%mm3, %%mm7 \n\t" /* add 4 high bytes to accumolator MM7 */ + /* --- */ + "movq %%mm4, %%mm2 \n\t" /* copy MM4 into MM2 */ + "psrlq $32, %%mm4 \n\t" /* shift 2 left words to the right */ + "psubw %%mm2, %%mm4 \n\t" /* MM4 = MM4 - MM2 */ + "movq %%mm6, %%mm3 \n\t" /* copy MM6 into MM3 */ + "psrlq $32, %%mm6 \n\t" /* shift 2 left words to the right */ + "psubw %%mm3, %%mm6 \n\t" /* MM6 = MM6 - MM3 */ + "punpckldq %%mm6, %%mm4 \n\t" /* combine 2 words of MM6 and 2 words of MM4 */ + "movq %%mm5, %%mm2 \n\t" /* copy MM6 into MM2 */ + "psrlq $32, %%mm5 \n\t" /* shift 2 left words to the right */ + "psubw %%mm2, %%mm5 \n\t" /* MM5 = MM5 - MM2 */ + "movq %%mm7, %%mm3 \n\t" /* copy MM7 into MM3 */ + "psrlq $32, %%mm7 \n\t" /* shift 2 left words to the right */ + "psubw %%mm3, %%mm7 \n\t" /* MM7 = MM7 - MM3 */ + "punpckldq %%mm7, %%mm5 \n\t" /* combine 2 words of MM7 and 2 words of MM5 */ + /* Take abs values of MM4 and MM5 */ + "movq %%mm4, %%mm6 \n\t" /* copy MM4 into MM6 */ + "movq %%mm5, %%mm7 \n\t" /* copy MM5 into MM7 */ + "psraw $15, %%mm6 \n\t" /* fill MM6 words with word sign bit */ + "psraw $15, %%mm7 \n\t" /* fill MM7 words with word sign bit */ + "pxor %%mm6, %%mm4 \n\t" /* take 1's compliment of only neg. words */ + "pxor %%mm7, %%mm5 \n\t" /* take 1's compliment of only neg. words */ + "psubsw %%mm6, %%mm4 \n\t" /* add 1 to only neg. words, W-(-1) or W-0 */ + "psubsw %%mm7, %%mm5 \n\t" /* add 1 to only neg. words, W-(-1) or W-0 */ + "packuswb %%mm5, %%mm4 \n\t" /* combine and pack/saturate MM5 and MM4 */ + "movq %%mm4, (%%edi) \n\t" /* store result in Dest */ + /* --- */ + "sub %%eax, %%esi \n\t" /* move to the current top row in Src */ + "sub %%eax, %%esi \n\t" "add $8, %%esi \n\t" /* move Src pointer to the next 8 pixels */ + "add $8, %%edi \n\t" /* move Dest pointer to the next 8 pixels */ + /* --- */ + "dec %%ecx \n\t" /* decrease loop counter COLUMNS */ + "jnz .L10412 \n\t" /* check loop termination, proceed if required */ + "mov %%ebx, %%esi \n\t" /* restore most left current row Src address */ + "mov %%edx, %%edi \n\t" /* restore most left current row Dest address */ + "add %%eax, %%esi \n\t" /* move to the next row in Src */ + "add %%eax, %%edi \n\t" /* move to the next row in Dest */ + "decl %2 \n\t" /* decrease loop counter ROWS */ + "jnz .L10410 \n\t" /* check loop termination, proceed if required */ + /* --- */ + "emms \n\t" /* exit MMX state */ + "popa \n\t":"=m" (Dest) /* %0 */ + :"m"(Src), /* %1 */ + "m"(rows), /* %2 */ + "m"(columns), /* %3 */ + "m"(NRightShift) /* %4 */ + ); +#endif +#endif + return (0); + } else { + /* No non-MMX implementation yet */ + return (-1); + } +} + +/*! +\brief Align stack to 32 byte boundary, +*/ +void SDL_imageFilterAlignStack(void) +{ +#ifdef USE_MMX +#if !defined(GCC__) + __asm + { /* --- stack alignment --- */ + mov ebx, esp /* load ESP into EBX */ + sub ebx, 4 /* reserve space on stack for old value of ESP */ + and ebx, -32 /* align EBX along a 32 byte boundary */ + mov [ebx], esp /* save old value of ESP in stack, behind the bndry */ + mov esp, ebx /* align ESP along a 32 byte boundary */ + } +#else + asm volatile + ( /* --- stack alignment --- */ + "mov %%esp, %%ebx \n\t" /* load ESP into EBX */ + "sub $4, %%ebx \n\t" /* reserve space on stack for old value of ESP */ + "and $-32, %%ebx \n\t" /* align EBX along a 32 byte boundary */ + "mov %%esp, (%%ebx) \n\t" /* save old value of ESP in stack, behind the bndry */ + "mov %%ebx, %%esp \n\t" /* align ESP along a 32 byte boundary */ + ::); +#endif +#endif +} + +/*! +\brief Restore previously aligned stack. +*/ +void SDL_imageFilterRestoreStack(void) +{ +#ifdef USE_MMX +#if !defined(GCC__) + __asm + { /* --- restoring old stack --- */ + mov ebx, [esp] /* load old value of ESP */ + mov esp, ebx /* restore old value of ESP */ + } +#else + asm volatile + ( /* --- restoring old stack --- */ + "mov (%%esp), %%ebx \n\t" /* load old value of ESP */ + "mov %%ebx, %%esp \n\t" /* restore old value of ESP */ + ::); +#endif +#endif +} diff --git a/engines/vileVN/external/SDL/gfx/SDL_imageFilter.h b/engines/vileVN/external/SDL/gfx/SDL_imageFilter.h new file mode 100644 index 0000000000..06278f38c5 --- /dev/null +++ b/engines/vileVN/external/SDL/gfx/SDL_imageFilter.h @@ -0,0 +1,195 @@ +/* + +SDL_imageFilter - bytes-image "filter" routines +(uses inline x86 MMX optimizations if available) + +LGPL (c) A. Schiffler + +*/ + +#ifndef _SDL_imageFilter_h +#define _SDL_imageFilter_h + +/* Set up for C function definitions, even when using C++ */ +#ifdef __cplusplus +extern "C" { +#endif + + /* ---- Function Prototypes */ + +#if defined(WIN32) || defined(WIN64) +# if defined(DLL_EXPORT) && !defined(LIBSDL_GFX_DLL_IMPORT) +# define SDL_IMAGEFILTER_SCOPE __declspec(dllexport) +# else +# ifdef LIBSDL_GFX_DLL_IMPORT +# define SDL_IMAGEFILTER_SCOPE __declspec(dllimport) +# endif +# endif +#endif +#ifndef SDL_IMAGEFILTER_SCOPE +# define SDL_IMAGEFILTER_SCOPE extern +#endif + + /* Comments: */ + /* 1.) MMX functions work best if all data blocks are aligned on a 32 bytes boundary. */ + /* 2.) Data that is not within an 8 byte boundary is processed using the C routine. */ + /* 3.) Convolution routines do not have C routines at this time. */ + + // Detect MMX capability in CPU + SDL_IMAGEFILTER_SCOPE int SDL_imageFilterMMXdetect(void); + + // Force use of MMX off (or turn possible use back on) + SDL_IMAGEFILTER_SCOPE void SDL_imageFilterMMXoff(void); + SDL_IMAGEFILTER_SCOPE void SDL_imageFilterMMXon(void); + + // + // All routines return: + // 0 OK + // -1 Error (internal error, parameter error) + // + + // SDL_imageFilterAdd: D = saturation255(S1 + S2) + SDL_IMAGEFILTER_SCOPE int SDL_imageFilterAdd(unsigned char *Src1, unsigned char *Src2, unsigned char *Dest, unsigned int length); + + // SDL_imageFilterMean: D = S1/2 + S2/2 + SDL_IMAGEFILTER_SCOPE int SDL_imageFilterMean(unsigned char *Src1, unsigned char *Src2, unsigned char *Dest, unsigned int length); + + // SDL_imageFilterSub: D = saturation0(S1 - S2) + SDL_IMAGEFILTER_SCOPE int SDL_imageFilterSub(unsigned char *Src1, unsigned char *Src2, unsigned char *Dest, unsigned int length); + + // SDL_imageFilterAbsDiff: D = | S1 - S2 | + SDL_IMAGEFILTER_SCOPE int SDL_imageFilterAbsDiff(unsigned char *Src1, unsigned char *Src2, unsigned char *Dest, unsigned int length); + + // SDL_imageFilterMult: D = saturation(S1 * S2) + SDL_IMAGEFILTER_SCOPE int SDL_imageFilterMult(unsigned char *Src1, unsigned char *Src2, unsigned char *Dest, unsigned int length); + + // SDL_imageFilterMultNor: D = S1 * S2 (non-MMX) + SDL_IMAGEFILTER_SCOPE int SDL_imageFilterMultNor(unsigned char *Src1, unsigned char *Src2, unsigned char *Dest, unsigned int length); + + // SDL_imageFilterMultDivby2: D = saturation255(S1/2 * S2) + SDL_IMAGEFILTER_SCOPE int SDL_imageFilterMultDivby2(unsigned char *Src1, unsigned char *Src2, unsigned char *Dest, + unsigned int length); + + // SDL_imageFilterMultDivby4: D = saturation255(S1/2 * S2/2) + SDL_IMAGEFILTER_SCOPE int SDL_imageFilterMultDivby4(unsigned char *Src1, unsigned char *Src2, unsigned char *Dest, + unsigned int length); + + // SDL_imageFilterBitAnd: D = S1 & S2 + SDL_IMAGEFILTER_SCOPE int SDL_imageFilterBitAnd(unsigned char *Src1, unsigned char *Src2, unsigned char *Dest, unsigned int length); + + // SDL_imageFilterBitOr: D = S1 | S2 + SDL_IMAGEFILTER_SCOPE int SDL_imageFilterBitOr(unsigned char *Src1, unsigned char *Src2, unsigned char *Dest, unsigned int length); + + // SDL_imageFilterDiv: D = S1 / S2 (non-MMX) + SDL_IMAGEFILTER_SCOPE int SDL_imageFilterDiv(unsigned char *Src1, unsigned char *Src2, unsigned char *Dest, unsigned int length); + + // SDL_imageFilterBitNegation: D = !S + SDL_IMAGEFILTER_SCOPE int SDL_imageFilterBitNegation(unsigned char *Src1, unsigned char *Dest, unsigned int length); + + // SDL_imageFilterAddByte: D = saturation255(S + C) + SDL_IMAGEFILTER_SCOPE int SDL_imageFilterAddByte(unsigned char *Src1, unsigned char *Dest, unsigned int length, unsigned char C); + + // SDL_imageFilterAddUint: D = saturation255(S + (uint)C) + SDL_IMAGEFILTER_SCOPE int SDL_imageFilterAddUint(unsigned char *Src1, unsigned char *Dest, unsigned int length, unsigned int C); + + // SDL_imageFilterAddByteToHalf: D = saturation255(S/2 + C) + SDL_IMAGEFILTER_SCOPE int SDL_imageFilterAddByteToHalf(unsigned char *Src1, unsigned char *Dest, unsigned int length, + unsigned char C); + + // SDL_imageFilterSubByte: D = saturation0(S - C) + SDL_IMAGEFILTER_SCOPE int SDL_imageFilterSubByte(unsigned char *Src1, unsigned char *Dest, unsigned int length, unsigned char C); + + // SDL_imageFilterSubUint: D = saturation0(S - (uint)C) + SDL_IMAGEFILTER_SCOPE int SDL_imageFilterSubUint(unsigned char *Src1, unsigned char *Dest, unsigned int length, unsigned int C); + + // SDL_imageFilterShiftRight: D = saturation0(S >> N) + SDL_IMAGEFILTER_SCOPE int SDL_imageFilterShiftRight(unsigned char *Src1, unsigned char *Dest, unsigned int length, unsigned char N); + + // SDL_imageFilterShiftRightUint: D = saturation0((uint)S >> N) + SDL_IMAGEFILTER_SCOPE int SDL_imageFilterShiftRightUint(unsigned char *Src1, unsigned char *Dest, unsigned int length, unsigned char N); + + // SDL_imageFilterMultByByte: D = saturation255(S * C) + SDL_IMAGEFILTER_SCOPE int SDL_imageFilterMultByByte(unsigned char *Src1, unsigned char *Dest, unsigned int length, unsigned char C); + + // SDL_imageFilterShiftRightAndMultByByte: D = saturation255((S >> N) * C) + SDL_IMAGEFILTER_SCOPE int SDL_imageFilterShiftRightAndMultByByte(unsigned char *Src1, unsigned char *Dest, unsigned int length, + unsigned char N, unsigned char C); + + // SDL_imageFilterShiftLeftByte: D = (S << N) + SDL_IMAGEFILTER_SCOPE int SDL_imageFilterShiftLeftByte(unsigned char *Src1, unsigned char *Dest, unsigned int length, + unsigned char N); + + // SDL_imageFilterShiftLeftUint: D = ((uint)S << N) + SDL_IMAGEFILTER_SCOPE int SDL_imageFilterShiftLeftUint(unsigned char *Src1, unsigned char *Dest, unsigned int length, + unsigned char N); + + // SDL_imageFilterShiftLeft: D = saturation255(S << N) + SDL_IMAGEFILTER_SCOPE int SDL_imageFilterShiftLeft(unsigned char *Src1, unsigned char *Dest, unsigned int length, unsigned char N); + + // SDL_imageFilterBinarizeUsingThreshold: D = S >= T ? 255:0 + SDL_IMAGEFILTER_SCOPE int SDL_imageFilterBinarizeUsingThreshold(unsigned char *Src1, unsigned char *Dest, unsigned int length, + unsigned char T); + + // SDL_imageFilterClipToRange: D = (S >= Tmin) & (S <= Tmax) 255:0 + SDL_IMAGEFILTER_SCOPE int SDL_imageFilterClipToRange(unsigned char *Src1, unsigned char *Dest, unsigned int length, + unsigned char Tmin, unsigned char Tmax); + + // SDL_imageFilterNormalizeLinear: D = saturation255((Nmax - Nmin)/(Cmax - Cmin)*(S - Cmin) + Nmin) + SDL_IMAGEFILTER_SCOPE int SDL_imageFilterNormalizeLinear(unsigned char *Src, unsigned char *Dest, unsigned int length, int Cmin, + int Cmax, int Nmin, int Nmax); + + /* !!! NO C-ROUTINE FOR THESE FUNCTIONS YET !!! */ + + // SDL_imageFilterConvolveKernel3x3Divide: Dij = saturation0and255( ... ) + SDL_IMAGEFILTER_SCOPE int SDL_imageFilterConvolveKernel3x3Divide(unsigned char *Src, unsigned char *Dest, int rows, + int columns, signed short *Kernel, unsigned char Divisor); + + // SDL_imageFilterConvolveKernel5x5Divide: Dij = saturation0and255( ... ) + SDL_IMAGEFILTER_SCOPE int SDL_imageFilterConvolveKernel5x5Divide(unsigned char *Src, unsigned char *Dest, int rows, + int columns, signed short *Kernel, unsigned char Divisor); + + // SDL_imageFilterConvolveKernel7x7Divide: Dij = saturation0and255( ... ) + SDL_IMAGEFILTER_SCOPE int SDL_imageFilterConvolveKernel7x7Divide(unsigned char *Src, unsigned char *Dest, int rows, + int columns, signed short *Kernel, unsigned char Divisor); + + // SDL_imageFilterConvolveKernel9x9Divide: Dij = saturation0and255( ... ) + SDL_IMAGEFILTER_SCOPE int SDL_imageFilterConvolveKernel9x9Divide(unsigned char *Src, unsigned char *Dest, int rows, + int columns, signed short *Kernel, unsigned char Divisor); + + // SDL_imageFilterConvolveKernel3x3ShiftRight: Dij = saturation0and255( ... ) + SDL_IMAGEFILTER_SCOPE int SDL_imageFilterConvolveKernel3x3ShiftRight(unsigned char *Src, unsigned char *Dest, int rows, + int columns, signed short *Kernel, + unsigned char NRightShift); + + // SDL_imageFilterConvolveKernel5x5ShiftRight: Dij = saturation0and255( ... ) + SDL_IMAGEFILTER_SCOPE int SDL_imageFilterConvolveKernel5x5ShiftRight(unsigned char *Src, unsigned char *Dest, int rows, + int columns, signed short *Kernel, + unsigned char NRightShift); + + // SDL_imageFilterConvolveKernel7x7ShiftRight: Dij = saturation0and255( ... ) + SDL_IMAGEFILTER_SCOPE int SDL_imageFilterConvolveKernel7x7ShiftRight(unsigned char *Src, unsigned char *Dest, int rows, + int columns, signed short *Kernel, + unsigned char NRightShift); + + // SDL_imageFilterConvolveKernel9x9ShiftRight: Dij = saturation0and255( ... ) + SDL_IMAGEFILTER_SCOPE int SDL_imageFilterConvolveKernel9x9ShiftRight(unsigned char *Src, unsigned char *Dest, int rows, + int columns, signed short *Kernel, + unsigned char NRightShift); + + // SDL_imageFilterSobelX: Dij = saturation255( ... ) + SDL_IMAGEFILTER_SCOPE int SDL_imageFilterSobelX(unsigned char *Src, unsigned char *Dest, int rows, int columns); + + // SDL_imageFilterSobelXShiftRight: Dij = saturation255( ... ) + SDL_IMAGEFILTER_SCOPE int SDL_imageFilterSobelXShiftRight(unsigned char *Src, unsigned char *Dest, int rows, int columns, + unsigned char NRightShift); + + // Align/restore stack to 32 byte boundary -- Functionality untested! -- + SDL_IMAGEFILTER_SCOPE void SDL_imageFilterAlignStack(void); + SDL_IMAGEFILTER_SCOPE void SDL_imageFilterRestoreStack(void); + + /* Ends C function definitions when using C++ */ +#ifdef __cplusplus +} +#endif + +#endif /* _SDL_imageFilter_h */ diff --git a/engines/vileVN/external/SDL/gfx/SDL_rotozoom.c b/engines/vileVN/external/SDL/gfx/SDL_rotozoom.c new file mode 100644 index 0000000000..5a20279ff6 --- /dev/null +++ b/engines/vileVN/external/SDL/gfx/SDL_rotozoom.c @@ -0,0 +1,1638 @@ +/* + +SDL_rotozoom.c - rotozoomer, zoomer and shrinker for 32bit or 8bit surfaces + +LGPL (c) A. Schiffler + +*/ + +#ifdef WIN32 +#include +#endif + +#include +#include + +#include "SDL_rotozoom.h" + +/* ---- Internally used structures */ + +/*! +\brief A 32 bit RGBA pixel. +*/ +typedef struct tColorRGBA { + Uint8 r; + Uint8 g; + Uint8 b; + Uint8 a; +} tColorRGBA; + +/*! +\brief A 8bit Y/palette pixel. +*/ +typedef struct tColorY { + Uint8 y; +} tColorY; + +/*! +\brief Returns maximum of two numbers a and b. +*/ +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) + +/*! +\brief Number of guard rows added to destination surfaces. + +This is a simple but effective workaround for observed issues. +These rows allocate extra memory and are then hidden from the surface. +Rows are added to the end of destination surfaces when they are allocated. +This catches any potential overflows which seem to happen with +just the right src image dimensions and scale/rotation and can lead +to a situation where the program can segfault. +*/ +#define GUARD_ROWS (2) + +/*! +\brief Lower limit of absolute zoom factor or rotation degrees. +*/ +#define VALUE_LIMIT 0.001 + +/*! +\brief Returns colorkey info for a surface +*/ +Uint32 _colorkey(SDL_Surface *src) +{ + Uint32 key = 0; +#if (SDL_MINOR_VERSION == 3) + SDL_GetColorKey(src, &key); +#else + if (src) + { + key = src->format->colorkey; + } +#endif + return key; +} + + +/*! +\brief Internal 32 bit integer-factor averaging Shrinker. + +Shrinks 32 bit RGBA/ABGR 'src' surface to 'dst' surface. +Averages color and alpha values values of src pixels to calculate dst pixels. +Assumes src and dst surfaces are of 32 bit depth. +Assumes dst surface was allocated with the correct dimensions. + +\param src The surface to shrink (input). +\param dst The shrunken surface (output). +\param factorx The horizontal shrinking ratio. +\param factory The vertical shrinking ratio. + +\return 0 for success or -1 for error. +*/ +int _shrinkSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int factorx, int factory) +{ + int x, y, dx, dy, sgap, dgap, ra, ga, ba, aa; + int n_average; + tColorRGBA *sp, *osp, *oosp; + tColorRGBA *dp; + + /* + * Averaging integer shrink + */ + + /* Precalculate division factor */ + n_average = factorx*factory; + + /* + * Scan destination + */ + sp = (tColorRGBA *) src->pixels; + sgap = src->pitch - src->w * 4; + + dp = (tColorRGBA *) dst->pixels; + dgap = dst->pitch - dst->w * 4; + + for (y = 0; y < dst->h; y++) { + + osp=sp; + for (x = 0; x < dst->w; x++) { + + /* Trace out source box and accumulate */ + oosp=sp; + ra=ga=ba=aa=0; + for (dy=0; dy < factory; dy++) { + for (dx=0; dx < factorx; dx++) { + ra += sp->r; + ga += sp->g; + ba += sp->b; + aa += sp->a; + + sp++; + } + /* src dx loop */ + sp = (tColorRGBA *)((Uint8*)sp + (src->pitch - 4*factorx)); // next y + } + /* src dy loop */ + + /* next box-x */ + sp = (tColorRGBA *)((Uint8*)oosp + 4*factorx); + + /* Store result in destination */ + dp->r = ra/n_average; + dp->g = ga/n_average; + dp->b = ba/n_average; + dp->a = aa/n_average; + + /* + * Advance destination pointer + */ + dp++; + } + /* dst x loop */ + + /* next box-y */ + sp = (tColorRGBA *)((Uint8*)osp + src->pitch*factory); + + /* + * Advance destination pointers + */ + dp = (tColorRGBA *) ((Uint8 *) dp + dgap); + } + /* dst y loop */ + + return (0); +} + +/*! +\brief Internal 8 bit integer-factor averaging shrinker. + +Shrinks 8bit Y 'src' surface to 'dst' surface. +Averages color (brightness) values values of src pixels to calculate dst pixels. +Assumes src and dst surfaces are of 8 bit depth. +Assumes dst surface was allocated with the correct dimensions. + +\param src The surface to shrink (input). +\param dst The shrunken surface (output). +\param factorx The horizontal shrinking ratio. +\param factory The vertical shrinking ratio. + +\return 0 for success or -1 for error. +*/ +int _shrinkSurfaceY(SDL_Surface * src, SDL_Surface * dst, int factorx, int factory) +{ + int x, y, dx, dy, sgap, dgap, a; + int n_average; + Uint8 *sp, *osp, *oosp; + Uint8 *dp; + + /* + * Averaging integer shrink + */ + + /* Precalculate division factor */ + n_average = factorx*factory; + + /* + * Scan destination + */ + sp = (Uint8 *) src->pixels; + sgap = src->pitch - src->w; + + dp = (Uint8 *) dst->pixels; + dgap = dst->pitch - dst->w; + + for (y = 0; y < dst->h; y++) { + + osp=sp; + for (x = 0; x < dst->w; x++) { + + /* Trace out source box and accumulate */ + oosp=sp; + a=0; + for (dy=0; dy < factory; dy++) { + for (dx=0; dx < factorx; dx++) { + a += (*sp); + /* next x */ + sp++; + } + /* end src dx loop */ + /* next y */ + sp = (Uint8 *)((Uint8*)sp + (src->pitch - factorx)); + } + /* end src dy loop */ + + /* next box-x */ + sp = (Uint8 *)((Uint8*)oosp + factorx); + + /* Store result in destination */ + *dp = a/n_average; + + /* + * Advance destination pointer + */ + dp++; + } + /* end dst x loop */ + + /* next box-y */ + sp = (Uint8 *)((Uint8*)osp + src->pitch*factory); + + /* + * Advance destination pointers + */ + dp = (Uint8 *)((Uint8 *)dp + dgap); + } + /* end dst y loop */ + + return (0); +} + +/*! +\brief Internal 32 bit Zoomer with optional anti-aliasing by bilinear interpolation. + +Zooms 32 bit RGBA/ABGR 'src' surface to 'dst' surface. +Assumes src and dst surfaces are of 32 bit depth. +Assumes dst surface was allocated with the correct dimensions. + +\param src The surface to zoom (input). +\param dst The zoomed surface (output). +\param flipx Flag indicating if the image should be horizontally flipped. +\param flipy Flag indicating if the image should be vertically flipped. +\param smooth Antialiasing flag; set to SMOOTHING_ON to enable. + +\return 0 for success or -1 for error. +*/ +int _zoomSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int flipx, int flipy, int smooth) +{ + int x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy, ex, ey, t1, t2, sstep, lx, ly; + tColorRGBA *c00, *c01, *c10, *c11, *cswap; + tColorRGBA *sp, *csp, *dp; + int dgap; + + /* + * Variable setup + */ + if (smooth) { + /* + * For interpolation: assume source dimension is one pixel + * smaller to avoid overflow on right and bottom edge. + */ + sx = (int) (65536.0 * (float) (src->w - 1) / (float) dst->w); + sy = (int) (65536.0 * (float) (src->h - 1) / (float) dst->h); + } else { + sx = (int) (65536.0 * (float) src->w / (float) dst->w); + sy = (int) (65536.0 * (float) src->h / (float) dst->h); + } + + /* + * Allocate memory for row increments + */ + if ((sax = (int *) malloc((dst->w + 1) * sizeof(Uint32))) == NULL) { + return (-1); + } + if ((say = (int *) malloc((dst->h + 1) * sizeof(Uint32))) == NULL) { + free(sax); + return (-1); + } + + /* + * Precalculate row increments + */ + sp = csp = (tColorRGBA *) src->pixels; + dp = (tColorRGBA *) dst->pixels; + + if (flipx) csp += (src->w-1); + if (flipy) csp += ((src->pitch/4)*(src->h-1)); + + csx = 0; + csax = sax; + for (x = 0; x <= dst->w; x++) { + *csax = csx; + csax++; + csx &= 0xffff; + csx += sx; + } + csy = 0; + csay = say; + for (y = 0; y <= dst->h; y++) { + *csay = csy; + csay++; + csy &= 0xffff; + csy += sy; + } + + dgap = dst->pitch - dst->w * 4; + + /* + * Switch between interpolating and non-interpolating code + */ + if (smooth) { + + /* + * Interpolating Zoom + */ + + /* + * Scan destination + */ + csay = say; + ly = 0; + for (y = 0; y < dst->h; y++) { + /* + * Setup color source pointers + */ + c00 = csp; + c01 = csp; + c01++; + c10 = csp; + c10 += src->pitch/4; + c11 = c10; + c11++; + if (flipx) { + cswap = c00; c00=c01; c01=cswap; + cswap = c10; c10=c11; c11=cswap; + } + if (flipy) { + cswap = c00; c00=c10; c10=cswap; + cswap = c01; c01=c11; c11=cswap; + } + + csax = sax; + lx = 0; + for (x = 0; x < dst->w; x++) { + /* + * Draw and interpolate colors + */ + ex = (*csax & 0xffff); + ey = (*csay & 0xffff); + t1 = ((((c01->r - c00->r) * ex) >> 16) + c00->r) & 0xff; + t2 = ((((c11->r - c10->r) * ex) >> 16) + c10->r) & 0xff; + dp->r = (((t2 - t1) * ey) >> 16) + t1; + t1 = ((((c01->g - c00->g) * ex) >> 16) + c00->g) & 0xff; + t2 = ((((c11->g - c10->g) * ex) >> 16) + c10->g) & 0xff; + dp->g = (((t2 - t1) * ey) >> 16) + t1; + t1 = ((((c01->b - c00->b) * ex) >> 16) + c00->b) & 0xff; + t2 = ((((c11->b - c10->b) * ex) >> 16) + c10->b) & 0xff; + dp->b = (((t2 - t1) * ey) >> 16) + t1; + t1 = ((((c01->a - c00->a) * ex) >> 16) + c00->a) & 0xff; + t2 = ((((c11->a - c10->a) * ex) >> 16) + c10->a) & 0xff; + dp->a = (((t2 - t1) * ey) >> 16) + t1; + + /* + * Advance source pointers + */ + csax++; + if (*csax > 0) + { + sstep = (*csax >> 16); + lx += sstep; + if (flipx) sstep = -sstep; + if (lx <= src->w) + { + c00 += sstep; + c01 += sstep; + c10 += sstep; + c11 += sstep; + } + } + + /* + * Advance destination pointer + */ + dp++; + } + + /* + * Advance source pointer + */ + csay++; + if (*csay > 0) + { + sstep = (*csay >> 16); + ly += sstep; + if (flipy) sstep = -sstep; + if (ly < src->h) + { + csp += (sstep * (src->pitch/4)); + } + } + + /* + * Advance destination pointers + */ + dp = (tColorRGBA *) ((Uint8 *) dp + dgap); + } + } else { + + /* + * Non-Interpolating Zoom + */ + csay = say; + for (y = 0; y < dst->h; y++) { + sp = csp; + csax = sax; + for (x = 0; x < dst->w; x++) { + /* + * Draw + */ + *dp = *sp; + /* + * Advance source pointers + */ + csax++; + if (*csax > 0) + { + sstep = (*csax >> 16); + if (flipx) sstep = -sstep; + sp += sstep; + } + /* + * Advance destination pointer + */ + dp++; + } + /* + * Advance source pointer + */ + csay++; + if (*csay > 0) + { + sstep = (*csay >> 16) * (src->pitch/4); + if (flipy) sstep = -sstep; + csp += sstep; + } + + /* + * Advance destination pointers + */ + dp = (tColorRGBA *) ((Uint8 *) dp + dgap); + } + } + + /* + * Remove temp arrays + */ + free(sax); + free(say); + + return (0); +} + +/*! + +\brief Internal 8 bit Zoomer without smoothing. + +Zooms 8bit palette/Y 'src' surface to 'dst' surface. +Assumes src and dst surfaces are of 8 bit depth. +Assumes dst surface was allocated with the correct dimensions. + +\param src The surface to zoom (input). +\param dst The zoomed surface (output). +\param flipx Flag indicating if the image should be horizontally flipped. +\param flipy Flag indicating if the image should be vertically flipped. + +\return 0 for success or -1 for error. +*/ +int _zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst, int flipx, int flipy) +{ + int x, y; + Uint32 *sax, *say, *csax, *csay; + int csx, csy; + Uint8 *sp, *dp, *csp; + int dgap; + + /* + * Allocate memory for row increments + */ + if ((sax = (Uint32 *) malloc((dst->w + 1) * sizeof(Uint32))) == NULL) { + return (-1); + } + if ((say = (Uint32 *) malloc((dst->h + 1) * sizeof(Uint32))) == NULL) { + free(sax); + return (-1); + } + + /* + * Pointer setup + */ + sp = csp = (Uint8 *) src->pixels; + dp = (Uint8 *) dst->pixels; + dgap = dst->pitch - dst->w; + + if (flipx) csp += (src->w-1); + if (flipy) csp = ( (Uint8*)csp + src->pitch*(src->h-1) ); + + /* + * Precalculate row increments + */ + csx = 0; + csax = sax; + for (x = 0; x < dst->w; x++) { + csx += src->w; + *csax = 0; + while (csx >= dst->w) { + csx -= dst->w; + (*csax)++; + } + csax++; + } + csy = 0; + csay = say; + for (y = 0; y < dst->h; y++) { + csy += src->h; + *csay = 0; + while (csy >= dst->h) { + csy -= dst->h; + (*csay)++; + } + csay++; + } + + /* + * Draw + */ + csay = say; + for (y = 0; y < dst->h; y++) { + csax = sax; + sp = csp; + for (x = 0; x < dst->w; x++) { + /* + * Draw + */ + *dp = *sp; + /* + * Advance source pointers + */ + sp += (*csax) * (flipx ? -1 : 1); + csax++; + /* + * Advance destination pointer + */ + dp++; + } + /* + * Advance source pointer (for row) + */ + csp += ((*csay) * src->pitch) * (flipy ? -1 : 1); + csay++; + + /* + * Advance destination pointers + */ + dp += dgap; + } + + /* + * Remove temp arrays + */ + free(sax); + free(say); + + return (0); +} + +/*! +\brief Internal 32 bit rotozoomer with optional anti-aliasing. + +Rotates and zooms 32 bit RGBA/ABGR 'src' surface to 'dst' surface based on the control +parameters by scanning the destination surface and applying optionally anti-aliasing +by bilinear interpolation. +Assumes src and dst surfaces are of 32 bit depth. +Assumes dst surface was allocated with the correct dimensions. + +\param src Source surface. +\param dst Destination surface. +\param cx Horizontal center coordinate. +\param cy Vertical center coordinate. +\param isin Integer version of sine of angle. +\param icos Integer version of cosine of angle. +\param flipx Flag indicating horizontal mirroring should be applied. +\param flipy Flag indicating vertical mirroring should be applied. +\param smooth Flag indicating anti-aliasing should be used. +*/ +void _transformSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int cx, int cy, int isin, int icos, int flipx, int flipy, int smooth) +{ + int x, y, t1, t2, dx, dy, xd, yd, sdx, sdy, ax, ay, ex, ey, sw, sh; + tColorRGBA c00, c01, c10, c11, cswap; + tColorRGBA *pc, *sp; + int gap; + + /* + * Variable setup + */ + xd = ((src->w - dst->w) << 15); + yd = ((src->h - dst->h) << 15); + ax = (cx << 16) - (icos * cx); + ay = (cy << 16) - (isin * cx); + sw = src->w - 1; + sh = src->h - 1; + pc = (tColorRGBA*) dst->pixels; + gap = dst->pitch - dst->w * 4; + + /* + * Switch between interpolating and non-interpolating code + */ + if (smooth) { + for (y = 0; y < dst->h; y++) { + dy = cy - y; + sdx = (ax + (isin * dy)) + xd; + sdy = (ay - (icos * dy)) + yd; + for (x = 0; x < dst->w; x++) { + dx = (sdx >> 16); + dy = (sdy >> 16); + if (flipx) dx = sw - dx; + if (flipy) dy = sh - dy; + if ((dx > -1) && (dy > -1) && (dx < (src->w-1)) && (dy < (src->h-1))) { + sp = (tColorRGBA *)src->pixels;; + sp += ((src->pitch/4) * dy); + sp += dx; + c00 = *sp; + sp += 1; + c01 = *sp; + sp += (src->pitch/4); + c11 = *sp; + sp -= 1; + c10 = *sp; + if (flipx) { + cswap = c00; c00=c01; c01=cswap; + cswap = c10; c10=c11; c11=cswap; + } + if (flipy) { + cswap = c00; c00=c10; c10=cswap; + cswap = c01; c01=c11; c11=cswap; + } + /* + * Interpolate colors + */ + ex = (sdx & 0xffff); + ey = (sdy & 0xffff); + t1 = ((((c01.r - c00.r) * ex) >> 16) + c00.r) & 0xff; + t2 = ((((c11.r - c10.r) * ex) >> 16) + c10.r) & 0xff; + pc->r = (((t2 - t1) * ey) >> 16) + t1; + t1 = ((((c01.g - c00.g) * ex) >> 16) + c00.g) & 0xff; + t2 = ((((c11.g - c10.g) * ex) >> 16) + c10.g) & 0xff; + pc->g = (((t2 - t1) * ey) >> 16) + t1; + t1 = ((((c01.b - c00.b) * ex) >> 16) + c00.b) & 0xff; + t2 = ((((c11.b - c10.b) * ex) >> 16) + c10.b) & 0xff; + pc->b = (((t2 - t1) * ey) >> 16) + t1; + t1 = ((((c01.a - c00.a) * ex) >> 16) + c00.a) & 0xff; + t2 = ((((c11.a - c10.a) * ex) >> 16) + c10.a) & 0xff; + pc->a = (((t2 - t1) * ey) >> 16) + t1; + } + sdx += icos; + sdy += isin; + pc++; + } + pc = (tColorRGBA *) ((Uint8 *) pc + gap); + } + } else { + for (y = 0; y < dst->h; y++) { + dy = cy - y; + sdx = (ax + (isin * dy)) + xd; + sdy = (ay - (icos * dy)) + yd; + for (x = 0; x < dst->w; x++) { + dx = (short) (sdx >> 16); + dy = (short) (sdy >> 16); + if (flipx) dx = (src->w-1)-dx; + if (flipy) dy = (src->h-1)-dy; + if ((dx >= 0) && (dy >= 0) && (dx < src->w) && (dy < src->h)) { + sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy); + sp += dx; + *pc = *sp; + } + sdx += icos; + sdy += isin; + pc++; + } + pc = (tColorRGBA *) ((Uint8 *) pc + gap); + } + } +} + +/*! + +\brief Rotates and zooms 8 bit palette/Y 'src' surface to 'dst' surface without smoothing. + +Rotates and zooms 8 bit RGBA/ABGR 'src' surface to 'dst' surface based on the control +parameters by scanning the destination surface. +Assumes src and dst surfaces are of 8 bit depth. +Assumes dst surface was allocated with the correct dimensions. + +\param src Source surface. +\param dst Destination surface. +\param cx Horizontal center coordinate. +\param cy Vertical center coordinate. +\param isin Integer version of sine of angle. +\param icos Integer version of cosine of angle. +\param flipx Flag indicating horizontal mirroring should be applied. +\param flipy Flag indicating vertical mirroring should be applied. +*/ +void transformSurfaceY(SDL_Surface * src, SDL_Surface * dst, int cx, int cy, int isin, int icos, int flipx, int flipy) +{ + int x, y, dx, dy, xd, yd, sdx, sdy, ax, ay, sw, sh; + tColorY *pc, *sp; + int gap; + + /* + * Variable setup + */ + xd = ((src->w - dst->w) << 15); + yd = ((src->h - dst->h) << 15); + ax = (cx << 16) - (icos * cx); + ay = (cy << 16) - (isin * cx); + sw = src->w - 1; + sh = src->h - 1; + pc = (tColorY*) dst->pixels; + gap = dst->pitch - dst->w; + /* + * Clear surface to colorkey + */ + memset(pc, (unsigned char) (_colorkey(src) & 0xff), dst->pitch * dst->h); + /* + * Iterate through destination surface + */ + for (y = 0; y < dst->h; y++) { + dy = cy - y; + sdx = (ax + (isin * dy)) + xd; + sdy = (ay - (icos * dy)) + yd; + for (x = 0; x < dst->w; x++) { + dx = (short) (sdx >> 16); + dy = (short) (sdy >> 16); + if (flipx) dx = (src->w-1)-dx; + if (flipy) dy = (src->h-1)-dy; + if ((dx >= 0) && (dy >= 0) && (dx < src->w) && (dy < src->h)) { + sp = (tColorY *) (src->pixels); + sp += (src->pitch * dy + dx); + *pc = *sp; + } + sdx += icos; + sdy += isin; + pc++; + } + pc += gap; + } +} + +/*! +\brief Rotates a 32 bit surface in increments of 90 degrees. + +Specialized 90 degree rotator which rotates a 'src' surface in 90 degree +increments clockwise returning a new surface. Faster than rotozoomer since +not scanning or interpolation takes place. Input surface must be 32 bit. +(code contributed by J. Schiller, improved by C. Allport and A. Schiffler) + +\param src Source surface to rotate. +\param numClockwiseTurns Number of clockwise 90 degree turns to apply to the source. + +\returns The new, rotated surface; or NULL for surfaces with incorrect input format. +*/ +SDL_Surface* rotateSurface90Degrees(SDL_Surface* src, int numClockwiseTurns) +{ + int row, col, newWidth, newHeight; + int bpp, src_ipr, dst_ipr; + SDL_Surface* dst; + Uint32* srcBuf; + Uint32* dstBuf; + + /* Has to be a valid surface pointer and only 32-bit surfaces (for now) */ + if (!src || src->format->BitsPerPixel != 32) { return NULL; } + + /* normalize numClockwiseTurns */ + while(numClockwiseTurns < 0) { numClockwiseTurns += 4; } + numClockwiseTurns = (numClockwiseTurns % 4); + + /* if it's even, our new width will be the same as the source surface */ + newWidth = (numClockwiseTurns % 2) ? (src->h) : (src->w); + newHeight = (numClockwiseTurns % 2) ? (src->w) : (src->h); + dst = SDL_CreateRGBSurface( src->flags, newWidth, newHeight, src->format->BitsPerPixel, + src->format->Rmask, + src->format->Gmask, + src->format->Bmask, + src->format->Amask); + if(!dst) { + return NULL; + } + + if (SDL_MUSTLOCK(dst)) { + SDL_LockSurface(dst); + } + if (SDL_MUSTLOCK(dst)) { + SDL_LockSurface(dst); + } + + /* Calculate int-per-row */ + bpp = src->format->BitsPerPixel / 8; + src_ipr = src->pitch / bpp; + dst_ipr = dst->pitch / bpp; + + switch(numClockwiseTurns) { + case 0: /* Make a copy of the surface */ + { + /* Unfortunately SDL_BlitSurface cannot be used to make a copy of the surface + since it does not preserve alpha. */ + + if (src->pitch == dst->pitch) { + /* If the pitch is the same for both surfaces, the memory can be copied all at once. */ + memcpy(dst->pixels, src->pixels, (src->h * src->pitch)); + } + else + { + /* If the pitch differs, copy each row separately */ + srcBuf = (Uint32*)(src->pixels); + dstBuf = (Uint32*)(dst->pixels); + for (row = 0; row < src->h; row++) { + memcpy(dstBuf, srcBuf, dst->w * bpp); + srcBuf += src_ipr; + dstBuf += dst_ipr; + } /* end for(col) */ + } /* end for(row) */ + } + break; + + /* rotate clockwise */ + case 1: /* rotated 90 degrees clockwise */ + { + for (row = 0; row < src->h; ++row) { + srcBuf = (Uint32*)(src->pixels) + (row * src_ipr); + dstBuf = (Uint32*)(dst->pixels) + (dst->w - row - 1); + for (col = 0; col < src->w; ++col) { + *dstBuf = *srcBuf; + ++srcBuf; + dstBuf += dst_ipr; + } + /* end for(col) */ + } + /* end for(row) */ + } + break; + + case 2: /* rotated 180 degrees clockwise */ + { + for (row = 0; row < src->h; ++row) { + srcBuf = (Uint32*)(src->pixels) + (row * src_ipr); + dstBuf = (Uint32*)(dst->pixels) + ((dst->h - row - 1) * dst_ipr) + (dst->w - 1); + for (col = 0; col < src->w; ++col) { + *dstBuf = *srcBuf; + ++srcBuf; + --dstBuf; + } + } + } + break; + + case 3: + { + for (row = 0; row < src->h; ++row) { + srcBuf = (Uint32*)(src->pixels) + (row * src_ipr); + dstBuf = (Uint32*)(dst->pixels) + row + ((dst->h - 1) * dst_ipr); + for (col = 0; col < src->w; ++col) { + *dstBuf = *srcBuf; + ++srcBuf; + dstBuf -= dst_ipr; + } + } + } + break; + } + /* end switch */ + + if (SDL_MUSTLOCK(src)) { + SDL_UnlockSurface(src); + } + if (SDL_MUSTLOCK(dst)) { + SDL_UnlockSurface(dst); + } + + return dst; +} + + +/*! +\brief Internal target surface sizing function for rotozooms with trig result return. + +\param width The source surface width. +\param height The source surface height. +\param angle The angle to rotate in degrees. +\param zoomx The horizontal scaling factor. +\param zoomy The vertical scaling factor. +\param dstwidth The calculated width of the destination surface. +\param dstheight The calculated height of the destination surface. +\param canglezoom The sine of the angle adjusted by the zoom factor. +\param sanglezoom The cosine of the angle adjusted by the zoom factor. + +*/ +void _rotozoomSurfaceSizeTrig(int width, int height, double angle, double zoomx, double zoomy, + int *dstwidth, int *dstheight, + double *canglezoom, double *sanglezoom) +{ + double x, y, cx, cy, sx, sy; + double radangle; + int dstwidthhalf, dstheighthalf; + + /* + * Determine destination width and height by rotating a centered source box + */ + radangle = angle * (M_PI / 180.0); + *sanglezoom = sin(radangle); + *canglezoom = cos(radangle); + *sanglezoom *= zoomx; + *canglezoom *= zoomx; + x = width / 2; + y = height / 2; + cx = *canglezoom * x; + cy = *canglezoom * y; + sx = *sanglezoom * x; + sy = *sanglezoom * y; + + dstwidthhalf = MAX((int) + ceil(MAX(MAX(MAX(fabs(cx + sy), fabs(cx - sy)), fabs(-cx + sy)), fabs(-cx - sy))), 1); + dstheighthalf = MAX((int) + ceil(MAX(MAX(MAX(fabs(sx + cy), fabs(sx - cy)), fabs(-sx + cy)), fabs(-sx - cy))), 1); + *dstwidth = 2 * dstwidthhalf; + *dstheight = 2 * dstheighthalf; +} + +/*! +\brief Returns the size of the resulting target surface for a rotozoomSurfaceXY() call. + +\param width The source surface width. +\param height The source surface height. +\param angle The angle to rotate in degrees. +\param zoomx The horizontal scaling factor. +\param zoomy The vertical scaling factor. +\param dstwidth The calculated width of the rotozoomed destination surface. +\param dstheight The calculated height of the rotozoomed destination surface. +*/ +void rotozoomSurfaceSizeXY(int width, int height, double angle, double zoomx, double zoomy, int *dstwidth, int *dstheight) +{ + double dummy_sanglezoom, dummy_canglezoom; + + _rotozoomSurfaceSizeTrig(width, height, angle, zoomx, zoomy, dstwidth, dstheight, &dummy_sanglezoom, &dummy_canglezoom); +} + +/*! +\brief Returns the size of the resulting target surface for a rotozoomSurface() call. + +\param width The source surface width. +\param height The source surface height. +\param angle The angle to rotate in degrees. +\param zoom The scaling factor. +\param dstwidth The calculated width of the rotozoomed destination surface. +\param dstheight The calculated height of the rotozoomed destination surface. +*/ +void rotozoomSurfaceSize(int width, int height, double angle, double zoom, int *dstwidth, int *dstheight) +{ + double dummy_sanglezoom, dummy_canglezoom; + + _rotozoomSurfaceSizeTrig(width, height, angle, zoom, zoom, dstwidth, dstheight, &dummy_sanglezoom, &dummy_canglezoom); +} + +/*! +\brief Rotates and zooms a surface and optional anti-aliasing. + +Rotates and zoomes a 32bit or 8bit 'src' surface to newly created 'dst' surface. +'angle' is the rotation in degrees and 'zoom' a scaling factor. If 'smooth' is set +then the destination 32bit surface is anti-aliased. If the surface is not 8bit +or 32bit RGBA/ABGR it will be converted into a 32bit RGBA format on the fly. + +\param src The surface to rotozoom. +\param angle The angle to rotate in degrees. +\param zoom The scaling factor. +\param smooth Antialiasing flag; set to SMOOTHING_ON to enable. + +\return The new rotozoomed surface. +*/ +SDL_Surface *rotozoomSurface(SDL_Surface * src, double angle, double zoom, int smooth) +{ + return rotozoomSurfaceXY(src, angle, zoom, zoom, smooth); +} + +/*! +\brief Rotates and zooms a surface with different horizontal and vertival scaling factors and optional anti-aliasing. + +Rotates and zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface. +'angle' is the rotation in degrees, 'zoomx and 'zoomy' scaling factors. If 'smooth' is set +then the destination 32bit surface is anti-aliased. If the surface is not 8bit +or 32bit RGBA/ABGR it will be converted into a 32bit RGBA format on the fly. + +\param src The surface to rotozoom. +\param angle The angle to rotate in degrees. +\param zoomx The horizontal scaling factor. +\param zoomy The vertical scaling factor. +\param smooth Antialiasing flag; set to SMOOTHING_ON to enable. + +\return The new rotozoomed surface. +*/ +SDL_Surface *rotozoomSurfaceXY(SDL_Surface * src, double angle, double zoomx, double zoomy, int smooth) +{ + SDL_Surface *rz_src; + SDL_Surface *rz_dst; + double zoominv; + double sanglezoom, canglezoom, sanglezoominv, canglezoominv; + int dstwidthhalf, dstwidth, dstheighthalf, dstheight; + int is32bit; + int i, src_converted; + int flipx,flipy; + Uint8 r,g,b; + Uint32 colorkey = 0; + int colorKeyAvailable = 0; + + /* + * Sanity check + */ + if (src == NULL) + return (NULL); + + if (src->flags & SDL_SRCCOLORKEY) + { + colorkey = _colorkey(src); + SDL_GetRGB(colorkey, src->format, &r, &g, &b); + colorKeyAvailable = 1; + } + /* + * Determine if source surface is 32bit or 8bit + */ + is32bit = (src->format->BitsPerPixel == 32); + if ((is32bit) || (src->format->BitsPerPixel == 8)) { + /* + * Use source surface 'as is' + */ + rz_src = src; + src_converted = 0; + } else { + /* + * New source surface is 32bit with a defined RGBA ordering + */ + rz_src = + SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32, +#if SDL_BYTEORDER == SDL_LIL_ENDIAN + 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000 +#else + 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff +#endif + ); + if(colorKeyAvailable) + SDL_SetColorKey(src, 0, 0); + + SDL_BlitSurface(src, NULL, rz_src, NULL); + + if(colorKeyAvailable) + SDL_SetColorKey(src, SDL_SRCCOLORKEY, colorkey); + src_converted = 1; + is32bit = 1; + } + + /* + * Sanity check zoom factor + */ + flipx = (zoomx<0.0); + if (flipx) zoomx=-zoomx; + flipy = (zoomy<0.0); + if (flipy) zoomy=-zoomy; + if (zoomx < VALUE_LIMIT) zoomx = VALUE_LIMIT; + if (zoomy < VALUE_LIMIT) zoomy = VALUE_LIMIT; + zoominv = 65536.0 / (zoomx * zoomx); + + /* + * Check if we have a rotozoom or just a zoom + */ + if (fabs(angle) > VALUE_LIMIT) { + + /* + * Angle!=0: full rotozoom + */ + /* + * ----------------------- + */ + + /* Determine target size */ + _rotozoomSurfaceSizeTrig(rz_src->w, rz_src->h, angle, zoomx, zoomy, &dstwidth, &dstheight, &canglezoom, &sanglezoom); + + /* + * Calculate target factors from sin/cos and zoom + */ + sanglezoominv = sanglezoom; + canglezoominv = canglezoom; + sanglezoominv *= zoominv; + canglezoominv *= zoominv; + + /* Calculate half size */ + dstwidthhalf = dstwidth / 2; + dstheighthalf = dstheight / 2; + + /* + * Alloc space to completely contain the rotated surface + */ + rz_dst = NULL; + if (is32bit) { + /* + * Target surface is 32bit with source RGBA/ABGR ordering + */ + rz_dst = + SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 32, + rz_src->format->Rmask, rz_src->format->Gmask, + rz_src->format->Bmask, rz_src->format->Amask); + } else { + /* + * Target surface is 8bit + */ + rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 8, 0, 0, 0, 0); + } + + /* Check target */ + if (rz_dst == NULL) + return NULL; + + /* Adjust for guard rows */ + rz_dst->h = dstheight; + + if (colorKeyAvailable == 1){ + colorkey = SDL_MapRGB(rz_dst->format, r, g, b); + + SDL_FillRect(rz_dst, NULL, colorkey ); + } + + /* + * Lock source surface + */ + if (SDL_MUSTLOCK(rz_src)) { + SDL_LockSurface(rz_src); + } + + /* + * Check which kind of surface we have + */ + if (is32bit) { + /* + * Call the 32bit transformation routine to do the rotation (using alpha) + */ + _transformSurfaceRGBA(rz_src, rz_dst, dstwidthhalf, dstheighthalf, + (int) (sanglezoominv), (int) (canglezoominv), + flipx, flipy, + smooth); + /* + * Turn on source-alpha support + */ + SDL_SetAlpha(rz_dst, SDL_SRCALPHA, 255); + SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, _colorkey(rz_src)); + } else { + /* + * Copy palette and colorkey info + */ + for (i = 0; i < rz_src->format->palette->ncolors; i++) { + rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i]; + } + rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors; + /* + * Call the 8bit transformation routine to do the rotation + */ + transformSurfaceY(rz_src, rz_dst, dstwidthhalf, dstheighthalf, + (int) (sanglezoominv), (int) (canglezoominv), + flipx, flipy); + SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, _colorkey(rz_src)); + } + /* + * Unlock source surface + */ + if (SDL_MUSTLOCK(rz_src)) { + SDL_UnlockSurface(rz_src); + } + + } else { + + /* + * Angle=0: Just a zoom + */ + /* + * -------------------- + */ + + /* + * Calculate target size + */ + zoomSurfaceSize(rz_src->w, rz_src->h, zoomx, zoomy, &dstwidth, &dstheight); + + /* + * Alloc space to completely contain the zoomed surface + */ + rz_dst = NULL; + if (is32bit) { + /* + * Target surface is 32bit with source RGBA/ABGR ordering + */ + rz_dst = + SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 32, + rz_src->format->Rmask, rz_src->format->Gmask, + rz_src->format->Bmask, rz_src->format->Amask); + } else { + /* + * Target surface is 8bit + */ + rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 8, 0, 0, 0, 0); + } + + /* Check target */ + if (rz_dst == NULL) + return NULL; + + /* Adjust for guard rows */ + rz_dst->h = dstheight; + + if (colorKeyAvailable == 1){ + colorkey = SDL_MapRGB(rz_dst->format, r, g, b); + + SDL_FillRect(rz_dst, NULL, colorkey ); + } + + /* + * Lock source surface + */ + if (SDL_MUSTLOCK(rz_src)) { + SDL_LockSurface(rz_src); + } + + /* + * Check which kind of surface we have + */ + if (is32bit) { + /* + * Call the 32bit transformation routine to do the zooming (using alpha) + */ + _zoomSurfaceRGBA(rz_src, rz_dst, flipx, flipy, smooth); + + /* + * Turn on source-alpha support + */ + SDL_SetAlpha(rz_dst, SDL_SRCALPHA, 255); + SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, _colorkey(rz_src)); + } else { + /* + * Copy palette and colorkey info + */ + for (i = 0; i < rz_src->format->palette->ncolors; i++) { + rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i]; + } + rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors; + + /* + * Call the 8bit transformation routine to do the zooming + */ + _zoomSurfaceY(rz_src, rz_dst, flipx, flipy); + SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, _colorkey(rz_src)); + } + + /* + * Unlock source surface + */ + if (SDL_MUSTLOCK(rz_src)) { + SDL_UnlockSurface(rz_src); + } + } + + /* + * Cleanup temp surface + */ + if (src_converted) { + SDL_FreeSurface(rz_src); + } + + /* + * Return destination surface + */ + return (rz_dst); +} + +/*! +\brief Calculates the size of the target surface for a zoomSurface() call. + +The minimum size of the target surface is 1. The input factors can be positive or negative. + +\param width The width of the source surface to zoom. +\param height The height of the source surface to zoom. +\param zoomx The horizontal zoom factor. +\param zoomy The vertical zoom factor. +\param dstwidth Pointer to an integer to store the calculated width of the zoomed target surface. +\param dstheight Pointer to an integer to store the calculated height of the zoomed target surface. +*/ +void zoomSurfaceSize(int width, int height, double zoomx, double zoomy, int *dstwidth, int *dstheight) +{ + /* + * Make zoom factors positive + */ + int flipx, flipy; + flipx = (zoomx<0.0); + if (flipx) zoomx = -zoomx; + flipy = (zoomy<0.0); + if (flipy) zoomy = -zoomy; + + /* + * Sanity check zoom factors + */ + if (zoomx < VALUE_LIMIT) { + zoomx = VALUE_LIMIT; + } + if (zoomy < VALUE_LIMIT) { + zoomy = VALUE_LIMIT; + } + + /* + * Calculate target size + */ + *dstwidth = (int) ((double) width * zoomx); + *dstheight = (int) ((double) height * zoomy); + if (*dstwidth < 1) { + *dstwidth = 1; + } + if (*dstheight < 1) { + *dstheight = 1; + } +} + +/*! +\brief Zoom a surface by independent horizontal and vertical factors with optional smoothing. + +Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface. +'zoomx' and 'zoomy' are scaling factors for width and height. If 'smooth' is on +then the destination 32bit surface is anti-aliased. If the surface is not 8bit +or 32bit RGBA/ABGR it will be converted into a 32bit RGBA format on the fly. +If zoom factors are negative, the image is flipped on the axes. + +\param src The surface to zoom. +\param zoomx The horizontal zoom factor. +\param zoomy The vertical zoom factor. +\param smooth Antialiasing flag; set to SMOOTHING_ON to enable. + +\return The new, zoomed surface. +*/ +SDL_Surface *zoomSurface(SDL_Surface * src, double zoomx, double zoomy, int smooth) +{ + SDL_Surface *rz_src; + SDL_Surface *rz_dst; + int dstwidth, dstheight; + int is32bit; + int i, src_converted; + int flipx, flipy; + + /* + * Sanity check + */ + if (src == NULL) + return (NULL); + + /* + * Determine if source surface is 32bit or 8bit + */ + is32bit = (src->format->BitsPerPixel == 32); + if ((is32bit) || (src->format->BitsPerPixel == 8)) { + /* + * Use source surface 'as is' + */ + rz_src = src; + src_converted = 0; + } else { + /* + * New source surface is 32bit with a defined RGBA ordering + */ + rz_src = + SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32, +#if SDL_BYTEORDER == SDL_LIL_ENDIAN + 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000 +#else + 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff +#endif + ); + SDL_BlitSurface(src, NULL, rz_src, NULL); + src_converted = 1; + is32bit = 1; + } + + flipx = (zoomx<0.0); + if (flipx) zoomx = -zoomx; + flipy = (zoomy<0.0); + if (flipy) zoomy = -zoomy; + + /* Get size if target */ + zoomSurfaceSize(rz_src->w, rz_src->h, zoomx, zoomy, &dstwidth, &dstheight); + + /* + * Alloc space to completely contain the zoomed surface + */ + rz_dst = NULL; + if (is32bit) { + /* + * Target surface is 32bit with source RGBA/ABGR ordering + */ + rz_dst = + SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 32, + rz_src->format->Rmask, rz_src->format->Gmask, + rz_src->format->Bmask, rz_src->format->Amask); + } else { + /* + * Target surface is 8bit + */ + rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 8, 0, 0, 0, 0); + } + + /* Check target */ + if (rz_dst == NULL) + return NULL; + + /* Adjust for guard rows */ + rz_dst->h = dstheight; + + /* + * Lock source surface + */ + if (SDL_MUSTLOCK(rz_src)) { + SDL_LockSurface(rz_src); + } + + /* + * Check which kind of surface we have + */ + if (is32bit) { + /* + * Call the 32bit transformation routine to do the zooming (using alpha) + */ + _zoomSurfaceRGBA(rz_src, rz_dst, flipx, flipy, smooth); + /* + * Turn on source-alpha support + */ + SDL_SetAlpha(rz_dst, SDL_SRCALPHA, 255); + } else { + /* + * Copy palette and colorkey info + */ + for (i = 0; i < rz_src->format->palette->ncolors; i++) { + rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i]; + } + rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors; + /* + * Call the 8bit transformation routine to do the zooming + */ + _zoomSurfaceY(rz_src, rz_dst, flipx, flipy); + SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, _colorkey(rz_src)); + } + /* + * Unlock source surface + */ + if (SDL_MUSTLOCK(rz_src)) { + SDL_UnlockSurface(rz_src); + } + + /* + * Cleanup temp surface + */ + if (src_converted) { + SDL_FreeSurface(rz_src); + } + + /* + * Return destination surface + */ + return (rz_dst); +} + +/*! +\brief Shrink a surface by an integer ratio using averaging. + +Shrinks a 32bit or 8bit 'src' surface to a newly created 'dst' surface. +'factorx' and 'factory' are the shrinking ratios (i.e. 2=1/2 the size, +3=1/3 the size, etc.) The destination surface is antialiased by averaging +the source box RGBA or Y information. If the surface is not 8bit +or 32bit RGBA/ABGR it will be converted into a 32bit RGBA format on the fly. +The input surface is not modified. The output surface is newly allocated. + +\param src The surface to shrink. +\param factorx The horizontal shrinking ratio. +\param factory The vertical shrinking ratio. + +\return The new, shrunken surface. +*/ +SDL_Surface *shrinkSurface(SDL_Surface *src, int factorx, int factory) +{ + SDL_Surface *rz_src; + SDL_Surface *rz_dst; + int dstwidth, dstheight; + int is32bit; + int i, src_converted; + + /* + * Sanity check + */ + if (src == NULL) + return (NULL); + + /* + * Determine if source surface is 32bit or 8bit + */ + is32bit = (src->format->BitsPerPixel == 32); + if ((is32bit) || (src->format->BitsPerPixel == 8)) { + /* + * Use source surface 'as is' + */ + rz_src = src; + src_converted = 0; + } else { + /* + * New source surface is 32bit with a defined RGBA ordering + */ + rz_src = + SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32, +#if SDL_BYTEORDER == SDL_LIL_ENDIAN + 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000 +#else + 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff +#endif + ); + SDL_BlitSurface(src, NULL, rz_src, NULL); + src_converted = 1; + is32bit = 1; + } + + /* Get size for target */ + dstwidth=rz_src->w/factorx; + while (dstwidth*factorx>rz_src->w) { dstwidth--; } + dstheight=rz_src->h/factory; + while (dstheight*factory>rz_src->h) { dstheight--; } + + /* + * Alloc space to completely contain the shrunken surface + * (with added guard rows) + */ + rz_dst = NULL; + if (is32bit) { + /* + * Target surface is 32bit with source RGBA/ABGR ordering + */ + rz_dst = + SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 32, + rz_src->format->Rmask, rz_src->format->Gmask, + rz_src->format->Bmask, rz_src->format->Amask); + } else { + /* + * Target surface is 8bit + */ + rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 8, 0, 0, 0, 0); + } + + /* Check target */ + if (rz_dst == NULL) + return NULL; + + /* Adjust for guard rows */ + rz_dst->h = dstheight; + + /* + * Lock source surface + */ + if (SDL_MUSTLOCK(rz_src)) { + SDL_LockSurface(rz_src); + } + + /* + * Check which kind of surface we have + */ + if (is32bit) { + /* + * Call the 32bit transformation routine to do the shrinking (using alpha) + */ + _shrinkSurfaceRGBA(rz_src, rz_dst, factorx, factory); + /* + * Turn on source-alpha support + */ + SDL_SetAlpha(rz_dst, SDL_SRCALPHA, 255); + } else { + /* + * Copy palette and colorkey info + */ + for (i = 0; i < rz_src->format->palette->ncolors; i++) { + rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i]; + } + rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors; + /* + * Call the 8bit transformation routine to do the shrinking + */ + _shrinkSurfaceY(rz_src, rz_dst, factorx, factory); + SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, _colorkey(rz_src)); + } + + /* + * Unlock source surface + */ + if (SDL_MUSTLOCK(rz_src)) { + SDL_UnlockSurface(rz_src); + } + + /* + * Cleanup temp surface + */ + if (src_converted) { + SDL_FreeSurface(rz_src); + } + + /* + * Return destination surface + */ + return (rz_dst); +} diff --git a/engines/vileVN/external/SDL/gfx/SDL_rotozoom.h b/engines/vileVN/external/SDL/gfx/SDL_rotozoom.h new file mode 100644 index 0000000000..0fce281a66 --- /dev/null +++ b/engines/vileVN/external/SDL/gfx/SDL_rotozoom.h @@ -0,0 +1,103 @@ + +/* + +SDL_rotozoom - rotozoomer + +LGPL (c) A. Schiffler + +*/ + +#ifndef _SDL_rotozoom_h +#define _SDL_rotozoom_h + +#include + +/* Set up for C function definitions, even when using C++ */ +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef M_PI +#define M_PI 3.141592654 +#endif + +#include "SDL.h" + + /* ---- Defines */ + + /*! + \brief Disable anti-aliasing (no smoothing). + */ +#define SMOOTHING_OFF 0 + + /*! + \brief Enable anti-aliasing (smoothing). + */ +#define SMOOTHING_ON 1 + + /* ---- Function Prototypes */ + +#if defined(WIN32) || defined(WIN64) +# if defined(DLL_EXPORT) && !defined(LIBSDL_GFX_DLL_IMPORT) +# define SDL_ROTOZOOM_SCOPE __declspec(dllexport) +# else +# ifdef LIBSDL_GFX_DLL_IMPORT +# define SDL_ROTOZOOM_SCOPE __declspec(dllimport) +# endif +# endif +#endif +#ifndef SDL_ROTOZOOM_SCOPE +# define SDL_ROTOZOOM_SCOPE extern +#endif + + /* + + Rotozoom functions + + */ + + SDL_ROTOZOOM_SCOPE SDL_Surface *rotozoomSurface(SDL_Surface * src, double angle, double zoom, int smooth); + + SDL_ROTOZOOM_SCOPE SDL_Surface *rotozoomSurfaceXY + (SDL_Surface * src, double angle, double zoomx, double zoomy, int smooth); + + + SDL_ROTOZOOM_SCOPE void rotozoomSurfaceSize(int width, int height, double angle, double zoom, int *dstwidth, + int *dstheight); + + SDL_ROTOZOOM_SCOPE void rotozoomSurfaceSizeXY + (int width, int height, double angle, double zoomx, double zoomy, + int *dstwidth, int *dstheight); + + /* + + Zooming functions + + */ + + SDL_ROTOZOOM_SCOPE SDL_Surface *zoomSurface(SDL_Surface * src, double zoomx, double zoomy, int smooth); + + SDL_ROTOZOOM_SCOPE void zoomSurfaceSize(int width, int height, double zoomx, double zoomy, int *dstwidth, int *dstheight); + + /* + + Shrinking functions + + */ + + SDL_ROTOZOOM_SCOPE SDL_Surface *shrinkSurface(SDL_Surface * src, int factorx, int factory); + + /* + + Specialized rotation functions + + */ + + SDL_ROTOZOOM_SCOPE SDL_Surface* rotateSurface90Degrees(SDL_Surface* src, int numClockwiseTurns); + + /* Ends C function definitions when using C++ */ +#ifdef __cplusplus +} +#endif + +#endif /* _SDL_rotozoom_h */ diff --git a/engines/vileVN/external/SDL/image/IMG.c b/engines/vileVN/external/SDL/image/IMG.c new file mode 100644 index 0000000000..d40e8650c3 --- /dev/null +++ b/engines/vileVN/external/SDL/image/IMG.c @@ -0,0 +1,212 @@ +/* + SDL_image: An example image loading library for use with SDL + Copyright (C) 1997-2012 Sam Lantinga + + 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. +*/ + +/* A simple library to load images of various formats as SDL surfaces */ + +#include +#include +#include + +#include "SDL_image.h" + +#define ARRAYSIZE(a) (sizeof(a) / sizeof((a)[0])) + +/* Table of image detection and loading functions */ +static struct { + char *type; + int (SDLCALL *is)(SDL_RWops *src); + SDL_Surface *(SDLCALL *load)(SDL_RWops *src); +} supported[] = { + /* keep magicless formats first */ + { "TGA", NULL, IMG_LoadTGA_RW }, + { "CUR", IMG_isCUR, IMG_LoadCUR_RW }, + { "ICO", IMG_isICO, IMG_LoadICO_RW }, + { "BMP", IMG_isBMP, IMG_LoadBMP_RW }, + { "GIF", IMG_isGIF, IMG_LoadGIF_RW }, + { "JPG", IMG_isJPG, IMG_LoadJPG_RW }, + { "LBM", IMG_isLBM, IMG_LoadLBM_RW }, + { "PCX", IMG_isPCX, IMG_LoadPCX_RW }, + { "PNG", IMG_isPNG, IMG_LoadPNG_RW }, + { "PNM", IMG_isPNM, IMG_LoadPNM_RW }, /* P[BGP]M share code */ + { "TIF", IMG_isTIF, IMG_LoadTIF_RW }, + { "XCF", IMG_isXCF, IMG_LoadXCF_RW }, + { "XPM", IMG_isXPM, IMG_LoadXPM_RW }, + { "XV", IMG_isXV, IMG_LoadXV_RW }, + { "WEBP", IMG_isWEBP, IMG_LoadWEBP_RW }, +}; + +const SDL_version *IMG_Linked_Version(void) +{ + static SDL_version linked_version; + SDL_IMAGE_VERSION(&linked_version); + return(&linked_version); +} + +extern int IMG_InitJPG(); +extern void IMG_QuitJPG(); +extern int IMG_InitPNG(); +extern void IMG_QuitPNG(); +extern int IMG_InitTIF(); +extern void IMG_QuitTIF(); + +extern int IMG_InitWEBP(); +extern void IMG_QuitWEBP(); + +static int initialized = 0; + +int IMG_Init(int flags) +{ + int result = 0; + + if (flags & IMG_INIT_JPG) { + if ((initialized & IMG_INIT_JPG) || IMG_InitJPG() == 0) { + result |= IMG_INIT_JPG; + } + } + if (flags & IMG_INIT_PNG) { + if ((initialized & IMG_INIT_PNG) || IMG_InitPNG() == 0) { + result |= IMG_INIT_PNG; + } + } + if (flags & IMG_INIT_TIF) { + if ((initialized & IMG_INIT_TIF) || IMG_InitTIF() == 0) { + result |= IMG_INIT_TIF; + } + } + if (flags & IMG_INIT_WEBP) { + if ((initialized & IMG_INIT_WEBP) || IMG_InitWEBP() == 0) { + result |= IMG_INIT_WEBP; + } + } + initialized |= result; + + return (initialized); +} + +void IMG_Quit() +{ + if (initialized & IMG_INIT_JPG) { + IMG_QuitJPG(); + } + if (initialized & IMG_INIT_PNG) { + IMG_QuitPNG(); + } + if (initialized & IMG_INIT_TIF) { + IMG_QuitTIF(); + } + if (initialized & IMG_INIT_WEBP) { + IMG_QuitWEBP(); + } + initialized = 0; +} + +#if !defined(__APPLE__) || defined(SDL_IMAGE_USE_COMMON_BACKEND) +/* Load an image from a file */ +SDL_Surface *IMG_Load(const char *file) +{ + SDL_RWops *src = SDL_RWFromFile(file, "rb"); + char *ext = strrchr(file, '.'); + if(ext) { + ext++; + } + if(!src) { + /* The error message has been set in SDL_RWFromFile */ + return NULL; + } + return IMG_LoadTyped_RW(src, 1, ext); +} +#endif + +/* Load an image from an SDL datasource (for compatibility) */ +SDL_Surface *IMG_Load_RW(SDL_RWops *src, int freesrc) +{ + return IMG_LoadTyped_RW(src, freesrc, NULL); +} + +/* Portable case-insensitive string compare function */ +static int IMG_string_equals(const char *str1, const char *str2) +{ + while ( *str1 && *str2 ) { + if ( toupper((unsigned char)*str1) != + toupper((unsigned char)*str2) ) + break; + ++str1; + ++str2; + } + return (!*str1 && !*str2); +} + +/* Load an image from an SDL datasource, optionally specifying the type */ +SDL_Surface *IMG_LoadTyped_RW(SDL_RWops *src, int freesrc, char *type) +{ + int i; + SDL_Surface *image; + + /* Make sure there is something to do.. */ + if ( src == NULL ) { + IMG_SetError("Passed a NULL data source"); + return(NULL); + } + + /* See whether or not this data source can handle seeking */ + if ( SDL_RWseek(src, 0, RW_SEEK_CUR) < 0 ) { + IMG_SetError("Can't seek in this data source"); + if(freesrc) + SDL_RWclose(src); + return(NULL); + } + + /* Detect the type of image being loaded */ + image = NULL; + for ( i=0; i < ARRAYSIZE(supported); ++i ) { + if(supported[i].is) { + if(!supported[i].is(src)) + continue; + } else { + /* magicless format */ + if(!type + || !IMG_string_equals(type, supported[i].type)) + continue; + } +#ifdef DEBUG_IMGLIB + fprintf(stderr, "IMGLIB: Loading image as %s\n", + supported[i].type); +#endif + image = supported[i].load(src); + if(freesrc) + SDL_RWclose(src); + return image; + } + + if ( freesrc ) { + SDL_RWclose(src); + } + IMG_SetError("Unsupported image format"); + return NULL; +} + +/* Invert the alpha of a surface for use with OpenGL + This function is a no-op and only kept for backwards compatibility. + */ +int IMG_InvertAlpha(int on) +{ + return 1; +} diff --git a/engines/vileVN/external/SDL/image/IMG_bmp.c b/engines/vileVN/external/SDL/image/IMG_bmp.c new file mode 100644 index 0000000000..b3c7580bbf --- /dev/null +++ b/engines/vileVN/external/SDL/image/IMG_bmp.c @@ -0,0 +1,848 @@ +/* + SDL_image: An example image loading library for use with SDL + Copyright (C) 1997-2012 Sam Lantinga + + 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. +*/ + +#if !defined(__APPLE__) || defined(SDL_IMAGE_USE_COMMON_BACKEND) + +/* This is a BMP image file loading framework */ +/* ICO/CUR file support is here as well since it uses similar internal + * representation */ + +#include +#include + +#include "SDL_image.h" + +#ifdef LOAD_BMP + +/* See if an image is contained in a data source */ +int IMG_isBMP(SDL_RWops *src) +{ + int start; + int is_BMP; + char magic[2]; + + if ( !src ) + return 0; + start = SDL_RWtell(src); + is_BMP = 0; + if ( SDL_RWread(src, magic, sizeof(magic), 1) ) { + if ( strncmp(magic, "BM", 2) == 0 ) { + is_BMP = 1; + } + } + SDL_RWseek(src, start, RW_SEEK_SET); + return(is_BMP); +} + +static int IMG_isICOCUR(SDL_RWops *src, int type) +{ + int start; + int is_ICOCUR; + + /* The Win32 ICO file header (14 bytes) */ + Uint16 bfReserved; + Uint16 bfType; + Uint16 bfCount; + + if ( !src ) + return 0; + start = SDL_RWtell(src); + is_ICOCUR = 0; + bfReserved = SDL_ReadLE16(src); + bfType = SDL_ReadLE16(src); + bfCount = SDL_ReadLE16(src); + if ((bfReserved == 0) && (bfType == type) && (bfCount != 0)) + is_ICOCUR = 1; + SDL_RWseek(src, start, RW_SEEK_SET); + + return (is_ICOCUR); +} + +int IMG_isICO(SDL_RWops *src) +{ + return IMG_isICOCUR(src, 1); +} + +int IMG_isCUR(SDL_RWops *src) +{ + return IMG_isICOCUR(src, 2); +} + +#include "SDL_error.h" +#include "SDL_video.h" +#include "SDL_endian.h" + +/* Compression encodings for BMP files */ +#ifndef BI_RGB +#define BI_RGB 0 +#define BI_RLE8 1 +#define BI_RLE4 2 +#define BI_BITFIELDS 3 +#endif + +static int readRlePixels(SDL_Surface * surface, SDL_RWops * src, int isRle8) +{ + /* + | Sets the surface pixels from src. A bmp image is upside down. + */ + int pitch = surface->pitch; + int height = surface->h; + Uint8 *start = (Uint8 *)surface->pixels; + Uint8 *end = start + (height*pitch); + Uint8 *bits = end-pitch, *spot; + int ofs = 0; + Uint8 ch; + Uint8 needsPad; + +#define COPY_PIXEL(x) spot = &bits[ofs++]; if(spot >= start && spot < end) *spot = (x) + + for (;;) { + if ( !SDL_RWread(src, &ch, 1, 1) ) return 1; + /* + | encoded mode starts with a run length, and then a byte + | with two colour indexes to alternate between for the run + */ + if ( ch ) { + Uint8 pixel; + if ( !SDL_RWread(src, &pixel, 1, 1) ) return 1; + if ( isRle8 ) { /* 256-color bitmap, compressed */ + do { + COPY_PIXEL(pixel); + } while (--ch); + } else { /* 16-color bitmap, compressed */ + Uint8 pixel0 = pixel >> 4; + Uint8 pixel1 = pixel & 0x0F; + for (;;) { + COPY_PIXEL(pixel0); /* even count, high nibble */ + if (!--ch) break; + COPY_PIXEL(pixel1); /* odd count, low nibble */ + if (!--ch) break; + } + } + } else { + /* + | A leading zero is an escape; it may signal the end of the bitmap, + | a cursor move, or some absolute data. + | zero tag may be absolute mode or an escape + */ + if ( !SDL_RWread(src, &ch, 1, 1) ) return 1; + switch (ch) { + case 0: /* end of line */ + ofs = 0; + bits -= pitch; /* go to previous */ + break; + case 1: /* end of bitmap */ + return 0; /* success! */ + case 2: /* delta */ + if ( !SDL_RWread(src, &ch, 1, 1) ) return 1; + ofs += ch; + if ( !SDL_RWread(src, &ch, 1, 1) ) return 1; + bits -= (ch * pitch); + break; + default: /* no compression */ + if (isRle8) { + needsPad = ( ch & 1 ); + do { + Uint8 pixel; + if ( !SDL_RWread(src, &pixel, 1, 1) ) return 1; + COPY_PIXEL(pixel); + } while (--ch); + } else { + needsPad = ( ((ch+1)>>1) & 1 ); /* (ch+1)>>1: bytes size */ + for (;;) { + Uint8 pixel; + if ( !SDL_RWread(src, &pixel, 1, 1) ) return 1; + COPY_PIXEL(pixel >> 4); + if (!--ch) break; + COPY_PIXEL(pixel & 0x0F); + if (!--ch) break; + } + } + /* pad at even boundary */ + if ( needsPad && !SDL_RWread(src, &ch, 1, 1) ) return 1; + break; + } + } + } +} + +static SDL_Surface *LoadBMP_RW (SDL_RWops *src, int freesrc) +{ + SDL_bool was_error; + long fp_offset; + int bmpPitch; + int i, pad; + SDL_Surface *surface; + Uint32 Rmask; + Uint32 Gmask; + Uint32 Bmask; + Uint32 Amask; + SDL_Palette *palette; + Uint8 *bits; + Uint8 *top, *end; + SDL_bool topDown; + int ExpandBMP; + + /* The Win32 BMP file header (14 bytes) */ + char magic[2]; + Uint32 bfSize; + Uint16 bfReserved1; + Uint16 bfReserved2; + Uint32 bfOffBits; + + /* The Win32 BITMAPINFOHEADER struct (40 bytes) */ + Uint32 biSize; + Sint32 biWidth; + Sint32 biHeight; + Uint16 biPlanes; + Uint16 biBitCount; + Uint32 biCompression; + Uint32 biSizeImage; + Sint32 biXPelsPerMeter; + Sint32 biYPelsPerMeter; + Uint32 biClrUsed; + Uint32 biClrImportant; + + /* Make sure we are passed a valid data source */ + surface = NULL; + was_error = SDL_FALSE; + if ( src == NULL ) { + was_error = SDL_TRUE; + goto done; + } + + /* Read in the BMP file header */ + fp_offset = SDL_RWtell(src); + SDL_ClearError(); + if ( SDL_RWread(src, magic, 1, 2) != 2 ) { + SDL_Error(SDL_EFREAD); + was_error = SDL_TRUE; + goto done; + } + if ( strncmp(magic, "BM", 2) != 0 ) { + IMG_SetError("File is not a Windows BMP file"); + was_error = SDL_TRUE; + goto done; + } + bfSize = SDL_ReadLE32(src); + bfReserved1 = SDL_ReadLE16(src); + bfReserved2 = SDL_ReadLE16(src); + bfOffBits = SDL_ReadLE32(src); + + /* Read the Win32 BITMAPINFOHEADER */ + biSize = SDL_ReadLE32(src); + if ( biSize == 12 ) { + biWidth = (Uint32)SDL_ReadLE16(src); + biHeight = (Uint32)SDL_ReadLE16(src); + biPlanes = SDL_ReadLE16(src); + biBitCount = SDL_ReadLE16(src); + biCompression = BI_RGB; + biSizeImage = 0; + biXPelsPerMeter = 0; + biYPelsPerMeter = 0; + biClrUsed = 0; + biClrImportant = 0; + } else { + biWidth = SDL_ReadLE32(src); + biHeight = SDL_ReadLE32(src); + biPlanes = SDL_ReadLE16(src); + biBitCount = SDL_ReadLE16(src); + biCompression = SDL_ReadLE32(src); + biSizeImage = SDL_ReadLE32(src); + biXPelsPerMeter = SDL_ReadLE32(src); + biYPelsPerMeter = SDL_ReadLE32(src); + biClrUsed = SDL_ReadLE32(src); + biClrImportant = SDL_ReadLE32(src); + } + if (biHeight < 0) { + topDown = SDL_TRUE; + biHeight = -biHeight; + } else { + topDown = SDL_FALSE; + } + + /* Check for read error */ + if ( strcmp(SDL_GetError(), "") != 0 ) { + was_error = SDL_TRUE; + goto done; + } + + /* Expand 1 and 4 bit bitmaps to 8 bits per pixel */ + switch (biBitCount) { + case 1: + case 4: + ExpandBMP = biBitCount; + biBitCount = 8; + break; + default: + ExpandBMP = 0; + break; + } + + /* RLE4 and RLE8 BMP compression is supported */ + Rmask = Gmask = Bmask = Amask = 0; + switch (biCompression) { + case BI_RGB: + /* If there are no masks, use the defaults */ + if ( bfOffBits == (14+biSize) ) { + /* Default values for the BMP format */ + switch (biBitCount) { + case 15: + case 16: + Rmask = 0x7C00; + Gmask = 0x03E0; + Bmask = 0x001F; + break; + case 24: +#if SDL_BYTEORDER == SDL_BIG_ENDIAN + Rmask = 0x000000FF; + Gmask = 0x0000FF00; + Bmask = 0x00FF0000; +#else + Rmask = 0x00FF0000; + Gmask = 0x0000FF00; + Bmask = 0x000000FF; +#endif + break; + case 32: + Amask = 0xFF000000; + Rmask = 0x00FF0000; + Gmask = 0x0000FF00; + Bmask = 0x000000FF; + break; + default: + break; + } + break; + } + /* Fall through -- read the RGB masks */ + + default: + switch (biBitCount) { + case 15: + case 16: + Rmask = SDL_ReadLE32(src); + Gmask = SDL_ReadLE32(src); + Bmask = SDL_ReadLE32(src); + break; + case 32: + Rmask = SDL_ReadLE32(src); + Gmask = SDL_ReadLE32(src); + Bmask = SDL_ReadLE32(src); + Amask = SDL_ReadLE32(src); + break; + default: + break; + } + break; + } + + /* Create a compatible surface, note that the colors are RGB ordered */ + surface = SDL_CreateRGBSurface(SDL_SWSURFACE, + biWidth, biHeight, biBitCount, Rmask, Gmask, Bmask, Amask); + if ( surface == NULL ) { + was_error = SDL_TRUE; + goto done; + } + + /* Load the palette, if any */ + palette = (surface->format)->palette; + if ( palette ) { + if ( SDL_RWseek(src, fp_offset+14+biSize, RW_SEEK_SET) < 0 ) { + SDL_Error(SDL_EFSEEK); + was_error = SDL_TRUE; + goto done; + } + + /* + | guich: always use 1<colors[i].b, 1, 1); + SDL_RWread(src, &palette->colors[i].g, 1, 1); + SDL_RWread(src, &palette->colors[i].r, 1, 1); + palette->colors[i].unused = 0; + } + } else { + for ( i = 0; i < (int)biClrUsed; ++i ) { + SDL_RWread(src, &palette->colors[i].b, 1, 1); + SDL_RWread(src, &palette->colors[i].g, 1, 1); + SDL_RWread(src, &palette->colors[i].r, 1, 1); + SDL_RWread(src, &palette->colors[i].unused, 1, 1); + } + } + palette->ncolors = biClrUsed; + } + + /* Read the surface pixels. Note that the bmp image is upside down */ + if ( SDL_RWseek(src, fp_offset+bfOffBits, RW_SEEK_SET) < 0 ) { + SDL_Error(SDL_EFSEEK); + was_error = SDL_TRUE; + goto done; + } + if ((biCompression == BI_RLE4) || (biCompression == BI_RLE8)) { + was_error = readRlePixels(surface, src, biCompression == BI_RLE8); + if (was_error) IMG_SetError("Error reading from BMP"); + goto done; + } + top = (Uint8 *)surface->pixels; + end = (Uint8 *)surface->pixels+(surface->h*surface->pitch); + switch (ExpandBMP) { + case 1: + bmpPitch = (biWidth + 7) >> 3; + pad = (((bmpPitch)%4) ? (4-((bmpPitch)%4)) : 0); + break; + case 4: + bmpPitch = (biWidth + 1) >> 1; + pad = (((bmpPitch)%4) ? (4-((bmpPitch)%4)) : 0); + break; + default: + pad = ((surface->pitch%4) ? + (4-(surface->pitch%4)) : 0); + break; + } + if ( topDown ) { + bits = top; + } else { + bits = end - surface->pitch; + } + while ( bits >= top && bits < end ) { + switch (ExpandBMP) { + case 1: + case 4: { + Uint8 pixel = 0; + int shift = (8-ExpandBMP); + for ( i=0; iw; ++i ) { + if ( i%(8/ExpandBMP) == 0 ) { + if ( !SDL_RWread(src, &pixel, 1, 1) ) { + IMG_SetError( + "Error reading from BMP"); + was_error = SDL_TRUE; + goto done; + } + } + *(bits+i) = (pixel>>shift); + pixel <<= ExpandBMP; + } } + break; + + default: + if ( SDL_RWread(src, bits, 1, surface->pitch) + != surface->pitch ) { + SDL_Error(SDL_EFREAD); + was_error = SDL_TRUE; + goto done; + } +#if SDL_BYTEORDER == SDL_BIG_ENDIAN + /* Byte-swap the pixels if needed. Note that the 24bpp + case has already been taken care of above. */ + switch(biBitCount) { + case 15: + case 16: { + Uint16 *pix = (Uint16 *)bits; + for(i = 0; i < surface->w; i++) + pix[i] = SDL_Swap16(pix[i]); + break; + } + + case 32: { + Uint32 *pix = (Uint32 *)bits; + for(i = 0; i < surface->w; i++) + pix[i] = SDL_Swap32(pix[i]); + break; + } + } +#endif + break; + } + /* Skip padding bytes, ugh */ + if ( pad ) { + Uint8 padbyte; + for ( i=0; ipitch; + } else { + bits -= surface->pitch; + } + } +done: + if ( was_error ) { + if ( src ) { + SDL_RWseek(src, fp_offset, RW_SEEK_SET); + } + if ( surface ) { + SDL_FreeSurface(surface); + } + surface = NULL; + } + if ( freesrc && src ) { + SDL_RWclose(src); + } + return(surface); +} + +static Uint8 +SDL_Read8(SDL_RWops * src) +{ + Uint8 value; + + SDL_RWread(src, &value, 1, 1); + return (value); +} + +static SDL_Surface * +LoadICOCUR_RW(SDL_RWops * src, int type, int freesrc) +{ + SDL_bool was_error; + long fp_offset; + int bmpPitch; + int i, pad; + SDL_Surface *surface; + Uint32 Rmask; + Uint32 Gmask; + Uint32 Bmask; + Uint8 *bits; + int ExpandBMP; + int maxCol = 0; + int icoOfs = 0; + Uint32 palette[256]; + + /* The Win32 ICO file header (14 bytes) */ + Uint16 bfReserved; + Uint16 bfType; + Uint16 bfCount; + + /* The Win32 BITMAPINFOHEADER struct (40 bytes) */ + Uint32 biSize; + Sint32 biWidth; + Sint32 biHeight; + Uint16 biPlanes; + Uint16 biBitCount; + Uint32 biCompression; + Uint32 biSizeImage; + Sint32 biXPelsPerMeter; + Sint32 biYPelsPerMeter; + Uint32 biClrUsed; + Uint32 biClrImportant; + + /* Make sure we are passed a valid data source */ + surface = NULL; + was_error = SDL_FALSE; + if (src == NULL) { + was_error = SDL_TRUE; + goto done; + } + + /* Read in the ICO file header */ + fp_offset = SDL_RWtell(src); + SDL_ClearError(); + + bfReserved = SDL_ReadLE16(src); + bfType = SDL_ReadLE16(src); + bfCount = SDL_ReadLE16(src); + if ((bfReserved != 0) || (bfType != type) || (bfCount == 0)) { + IMG_SetError("File is not a Windows %s file", type == 1 ? "ICO" : "CUR"); + was_error = SDL_TRUE; + goto done; + } + + /* Read the Win32 Icon Directory */ + for (i = 0; i < bfCount; i++) { + /* Icon Directory Entries */ + int bWidth = SDL_Read8(src); /* Uint8, but 0 = 256 ! */ + int bHeight = SDL_Read8(src); /* Uint8, but 0 = 256 ! */ + int bColorCount = SDL_Read8(src); /* Uint8, but 0 = 256 ! */ + Uint8 bReserved = SDL_Read8(src); + Uint16 wPlanes = SDL_ReadLE16(src); + Uint16 wBitCount = SDL_ReadLE16(src); + Uint32 dwBytesInRes = SDL_ReadLE32(src); + Uint32 dwImageOffset = SDL_ReadLE32(src); + + if (!bWidth) + bWidth = 256; + if (!bHeight) + bHeight = 256; + if (!bColorCount) + bColorCount = 256; + + //printf("%dx%d@%d - %08x\n", bWidth, bHeight, bColorCount, dwImageOffset); + if (bColorCount > maxCol) { + maxCol = bColorCount; + icoOfs = dwImageOffset; + //printf("marked\n"); + } + } + + /* Advance to the DIB Data */ + if (SDL_RWseek(src, icoOfs, RW_SEEK_SET) < 0) { + SDL_Error(SDL_EFSEEK); + was_error = SDL_TRUE; + goto done; + } + + /* Read the Win32 BITMAPINFOHEADER */ + biSize = SDL_ReadLE32(src); + if (biSize == 40) { + biWidth = SDL_ReadLE32(src); + biHeight = SDL_ReadLE32(src); + biPlanes = SDL_ReadLE16(src); + biBitCount = SDL_ReadLE16(src); + biCompression = SDL_ReadLE32(src); + biSizeImage = SDL_ReadLE32(src); + biXPelsPerMeter = SDL_ReadLE32(src); + biYPelsPerMeter = SDL_ReadLE32(src); + biClrUsed = SDL_ReadLE32(src); + biClrImportant = SDL_ReadLE32(src); + } else { + IMG_SetError("Unsupported ICO bitmap format"); + was_error = SDL_TRUE; + goto done; + } + + /* Check for read error */ + if (SDL_strcmp(SDL_GetError(), "") != 0) { + was_error = SDL_TRUE; + goto done; + } + + /* We don't support any BMP compression right now */ + switch (biCompression) { + case BI_RGB: + /* Default values for the BMP format */ + switch (biBitCount) { + case 1: + case 4: + ExpandBMP = biBitCount; + biBitCount = 8; + break; + case 8: + ExpandBMP = 8; + break; + case 32: + Rmask = 0x00FF0000; + Gmask = 0x0000FF00; + Bmask = 0x000000FF; + ExpandBMP = 0; + break; + default: + IMG_SetError("ICO file with unsupported bit count"); + was_error = SDL_TRUE; + goto done; + } + break; + default: + IMG_SetError("Compressed ICO files not supported"); + was_error = SDL_TRUE; + goto done; + } + + /* Create a RGBA surface */ + biHeight = biHeight >> 1; + //printf("%d x %d\n", biWidth, biHeight); + surface = + SDL_CreateRGBSurface(0, biWidth, biHeight, 32, 0x00FF0000, + 0x0000FF00, 0x000000FF, 0xFF000000); + if (surface == NULL) { + was_error = SDL_TRUE; + goto done; + } + + /* Load the palette, if any */ + //printf("bc %d bused %d\n", biBitCount, biClrUsed); + if (biBitCount <= 8) { + if (biClrUsed == 0) { + biClrUsed = 1 << biBitCount; + } + for (i = 0; i < (int) biClrUsed; ++i) { + SDL_RWread(src, &palette[i], 4, 1); + } + } + + /* Read the surface pixels. Note that the bmp image is upside down */ + bits = (Uint8 *) surface->pixels + (surface->h * surface->pitch); + switch (ExpandBMP) { + case 1: + bmpPitch = (biWidth + 7) >> 3; + pad = (((bmpPitch) % 4) ? (4 - ((bmpPitch) % 4)) : 0); + break; + case 4: + bmpPitch = (biWidth + 1) >> 1; + pad = (((bmpPitch) % 4) ? (4 - ((bmpPitch) % 4)) : 0); + break; + case 8: + bmpPitch = biWidth; + pad = (((bmpPitch) % 4) ? (4 - ((bmpPitch) % 4)) : 0); + break; + default: + bmpPitch = biWidth * 4; + pad = 0; + break; + } + while (bits > (Uint8 *) surface->pixels) { + bits -= surface->pitch; + switch (ExpandBMP) { + case 1: + case 4: + case 8: + { + Uint8 pixel = 0; + int shift = (8 - ExpandBMP); + for (i = 0; i < surface->w; ++i) { + if (i % (8 / ExpandBMP) == 0) { + if (!SDL_RWread(src, &pixel, 1, 1)) { + IMG_SetError("Error reading from ICO"); + was_error = SDL_TRUE; + goto done; + } + } + *((Uint32 *) bits + i) = (palette[pixel >> shift]); + pixel <<= ExpandBMP; + } + } + break; + + default: + if (SDL_RWread(src, bits, 1, surface->pitch) + != surface->pitch) { + SDL_Error(SDL_EFREAD); + was_error = SDL_TRUE; + goto done; + } + break; + } + /* Skip padding bytes, ugh */ + if (pad) { + Uint8 padbyte; + for (i = 0; i < pad; ++i) { + SDL_RWread(src, &padbyte, 1, 1); + } + } + } + /* Read the mask pixels. Note that the bmp image is upside down */ + bits = (Uint8 *) surface->pixels + (surface->h * surface->pitch); + ExpandBMP = 1; + bmpPitch = (biWidth + 7) >> 3; + pad = (((bmpPitch) % 4) ? (4 - ((bmpPitch) % 4)) : 0); + while (bits > (Uint8 *) surface->pixels) { + Uint8 pixel = 0; + int shift = (8 - ExpandBMP); + + bits -= surface->pitch; + for (i = 0; i < surface->w; ++i) { + if (i % (8 / ExpandBMP) == 0) { + if (!SDL_RWread(src, &pixel, 1, 1)) { + IMG_SetError("Error reading from ICO"); + was_error = SDL_TRUE; + goto done; + } + } + *((Uint32 *) bits + i) |= ((pixel >> shift) ? 0 : 0xFF000000); + pixel <<= ExpandBMP; + } + /* Skip padding bytes, ugh */ + if (pad) { + Uint8 padbyte; + for (i = 0; i < pad; ++i) { + SDL_RWread(src, &padbyte, 1, 1); + } + } + } + done: + if (was_error) { + if (src) { + SDL_RWseek(src, fp_offset, RW_SEEK_SET); + } + if (surface) { + SDL_FreeSurface(surface); + } + surface = NULL; + } + if (freesrc && src) { + SDL_RWclose(src); + } + return (surface); +} + +/* Load a BMP type image from an SDL datasource */ +SDL_Surface *IMG_LoadBMP_RW(SDL_RWops *src) +{ + return(LoadBMP_RW(src, 0)); +} + +/* Load a ICO type image from an SDL datasource */ +SDL_Surface *IMG_LoadICO_RW(SDL_RWops *src) +{ + return(LoadICOCUR_RW(src, 1, 0)); +} + +/* Load a CUR type image from an SDL datasource */ +SDL_Surface *IMG_LoadCUR_RW(SDL_RWops *src) +{ + return(LoadICOCUR_RW(src, 2, 0)); +} + +#else + +/* See if an image is contained in a data source */ +int IMG_isBMP(SDL_RWops *src) +{ + return(0); +} + +int IMG_isICO(SDL_RWops *src) +{ + return(0); +} + +int IMG_isCUR(SDL_RWops *src) +{ + return(0); +} + +/* Load a BMP type image from an SDL datasource */ +SDL_Surface *IMG_LoadBMP_RW(SDL_RWops *src) +{ + return(NULL); +} + +/* Load a BMP type image from an SDL datasource */ +SDL_Surface *IMG_LoadCUR_RW(SDL_RWops *src) +{ + return(NULL); +} + +/* Load a BMP type image from an SDL datasource */ +SDL_Surface *IMG_LoadICO_RW(SDL_RWops *src) +{ + return(NULL); +} + +#endif /* LOAD_BMP */ + +#endif /* !defined(__APPLE__) || defined(SDL_IMAGE_USE_COMMON_BACKEND) */ diff --git a/engines/vileVN/external/SDL/image/IMG_gif.c b/engines/vileVN/external/SDL/image/IMG_gif.c new file mode 100644 index 0000000000..de93fa7718 --- /dev/null +++ b/engines/vileVN/external/SDL/image/IMG_gif.c @@ -0,0 +1,625 @@ +/* + SDL_image: An example image loading library for use with SDL + Copyright (C) 1997-2012 Sam Lantinga + + 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. +*/ + +#if !defined(__APPLE__) || defined(SDL_IMAGE_USE_COMMON_BACKEND) + +/* This is a GIF image file loading framework */ + +#include +#include + +#include "SDL_image.h" + +#ifdef LOAD_GIF + +/* See if an image is contained in a data source */ +int IMG_isGIF(SDL_RWops *src) +{ + int start; + int is_GIF; + char magic[6]; + + if ( !src ) + return 0; + start = SDL_RWtell(src); + is_GIF = 0; + if ( SDL_RWread(src, magic, sizeof(magic), 1) ) { + if ( (strncmp(magic, "GIF", 3) == 0) && + ((memcmp(magic + 3, "87a", 3) == 0) || + (memcmp(magic + 3, "89a", 3) == 0)) ) { + is_GIF = 1; + } + } + SDL_RWseek(src, start, RW_SEEK_SET); + return(is_GIF); +} + +/* Code from here to end of file has been adapted from XPaint: */ +/* +-------------------------------------------------------------------+ */ +/* | Copyright 1990, 1991, 1993 David Koblas. | */ +/* | Copyright 1996 Torsten Martinsen. | */ +/* | 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. This software is | */ +/* | provided "as is" without express or implied warranty. | */ +/* +-------------------------------------------------------------------+ */ + +/* Adapted for use in SDL by Sam Lantinga -- 7/20/98 */ +#define USED_BY_SDL + +#include +#include + +#ifdef USED_BY_SDL +/* Changes to work with SDL: + + Include SDL header file + Use SDL_Surface rather than xpaint Image structure + Define SDL versions of RWSetMsg(), ImageNewCmap() and ImageSetCmap() +*/ +#include "SDL.h" + +#define Image SDL_Surface +#define RWSetMsg IMG_SetError +#define ImageNewCmap(w, h, s) SDL_AllocSurface(SDL_SWSURFACE,w,h,8,0,0,0,0) +#define ImageSetCmap(s, i, R, G, B) do { \ + s->format->palette->colors[i].r = R; \ + s->format->palette->colors[i].g = G; \ + s->format->palette->colors[i].b = B; \ + } while (0) +/* * * * * */ + +#else + +/* Original XPaint sources */ + +#include "image.h" +#include "rwTable.h" + +#define SDL_RWops FILE +#define SDL_RWclose fclose + +#endif /* USED_BY_SDL */ + + +#define MAXCOLORMAPSIZE 256 + +#define TRUE 1 +#define FALSE 0 + +#define CM_RED 0 +#define CM_GREEN 1 +#define CM_BLUE 2 + +#define MAX_LWZ_BITS 12 + +#define INTERLACE 0x40 +#define LOCALCOLORMAP 0x80 +#define BitSet(byte, bit) (((byte) & (bit)) == (bit)) + +#define ReadOK(file,buffer,len) SDL_RWread(file, buffer, len, 1) + +#define LM_to_uint(a,b) (((b)<<8)|(a)) + +static struct { + unsigned int Width; + unsigned int Height; + unsigned char ColorMap[3][MAXCOLORMAPSIZE]; + unsigned int BitPixel; + unsigned int ColorResolution; + unsigned int Background; + unsigned int AspectRatio; + int GrayScale; +} GifScreen; + +static struct { + int transparent; + int delayTime; + int inputFlag; + int disposal; +} Gif89; + +static int ReadColorMap(SDL_RWops * src, int number, + unsigned char buffer[3][MAXCOLORMAPSIZE], int *flag); +static int DoExtension(SDL_RWops * src, int label); +static int GetDataBlock(SDL_RWops * src, unsigned char *buf); +static int GetCode(SDL_RWops * src, int code_size, int flag); +static int LWZReadByte(SDL_RWops * src, int flag, int input_code_size); +static Image *ReadImage(SDL_RWops * src, int len, int height, int, + unsigned char cmap[3][MAXCOLORMAPSIZE], + int gray, int interlace, int ignore); + +Image * +IMG_LoadGIF_RW(SDL_RWops *src) +{ + int start; + unsigned char buf[16]; + unsigned char c; + unsigned char localColorMap[3][MAXCOLORMAPSIZE]; + int grayScale; + int useGlobalColormap; + int bitPixel; + int imageCount = 0; + char version[4]; + int imageNumber = 1; + Image *image = NULL; + + if ( src == NULL ) { + return NULL; + } + start = SDL_RWtell(src); + + if (!ReadOK(src, buf, 6)) { + RWSetMsg("error reading magic number"); + goto done; + } + if (strncmp((char *) buf, "GIF", 3) != 0) { + RWSetMsg("not a GIF file"); + goto done; + } + memcpy(version, (char *) buf + 3, 3); + version[3] = '\0'; + + if ((strcmp(version, "87a") != 0) && (strcmp(version, "89a") != 0)) { + RWSetMsg("bad version number, not '87a' or '89a'"); + goto done; + } + Gif89.transparent = -1; + Gif89.delayTime = -1; + Gif89.inputFlag = -1; + Gif89.disposal = 0; + + if (!ReadOK(src, buf, 7)) { + RWSetMsg("failed to read screen descriptor"); + goto done; + } + GifScreen.Width = LM_to_uint(buf[0], buf[1]); + GifScreen.Height = LM_to_uint(buf[2], buf[3]); + GifScreen.BitPixel = 2 << (buf[4] & 0x07); + GifScreen.ColorResolution = (((buf[4] & 0x70) >> 3) + 1); + GifScreen.Background = buf[5]; + GifScreen.AspectRatio = buf[6]; + + if (BitSet(buf[4], LOCALCOLORMAP)) { /* Global Colormap */ + if (ReadColorMap(src, GifScreen.BitPixel, GifScreen.ColorMap, + &GifScreen.GrayScale)) { + RWSetMsg("error reading global colormap"); + goto done; + } + } + do { + if (!ReadOK(src, &c, 1)) { + RWSetMsg("EOF / read error on image data"); + goto done; + } + if (c == ';') { /* GIF terminator */ + if (imageCount < imageNumber) { + RWSetMsg("only %d image%s found in file", + imageCount, imageCount > 1 ? "s" : ""); + goto done; + } + } + if (c == '!') { /* Extension */ + if (!ReadOK(src, &c, 1)) { + RWSetMsg("EOF / read error on extention function code"); + goto done; + } + DoExtension(src, c); + continue; + } + if (c != ',') { /* Not a valid start character */ + continue; + } + ++imageCount; + + if (!ReadOK(src, buf, 9)) { + RWSetMsg("couldn't read left/top/width/height"); + goto done; + } + useGlobalColormap = !BitSet(buf[8], LOCALCOLORMAP); + + bitPixel = 1 << ((buf[8] & 0x07) + 1); + + if (!useGlobalColormap) { + if (ReadColorMap(src, bitPixel, localColorMap, &grayScale)) { + RWSetMsg("error reading local colormap"); + goto done; + } + image = ReadImage(src, LM_to_uint(buf[4], buf[5]), + LM_to_uint(buf[6], buf[7]), + bitPixel, localColorMap, grayScale, + BitSet(buf[8], INTERLACE), + imageCount != imageNumber); + } else { + image = ReadImage(src, LM_to_uint(buf[4], buf[5]), + LM_to_uint(buf[6], buf[7]), + GifScreen.BitPixel, GifScreen.ColorMap, + GifScreen.GrayScale, BitSet(buf[8], INTERLACE), + imageCount != imageNumber); + } + } while (image == NULL); + +#ifdef USED_BY_SDL + if ( Gif89.transparent >= 0 ) { + SDL_SetColorKey(image, SDL_SRCCOLORKEY, Gif89.transparent); + } +#endif + +done: + if ( image == NULL ) { + SDL_RWseek(src, start, RW_SEEK_SET); + } + return image; +} + +static int +ReadColorMap(SDL_RWops *src, int number, + unsigned char buffer[3][MAXCOLORMAPSIZE], int *gray) +{ + int i; + unsigned char rgb[3]; + int flag; + + flag = TRUE; + + for (i = 0; i < number; ++i) { + if (!ReadOK(src, rgb, sizeof(rgb))) { + RWSetMsg("bad colormap"); + return 1; + } + buffer[CM_RED][i] = rgb[0]; + buffer[CM_GREEN][i] = rgb[1]; + buffer[CM_BLUE][i] = rgb[2]; + flag &= (rgb[0] == rgb[1] && rgb[1] == rgb[2]); + } + +#if 0 + if (flag) + *gray = (number == 2) ? PBM_TYPE : PGM_TYPE; + else + *gray = PPM_TYPE; +#else + *gray = 0; +#endif + + return FALSE; +} + +static int +DoExtension(SDL_RWops *src, int label) +{ + static unsigned char buf[256]; + char *str; + + switch (label) { + case 0x01: /* Plain Text Extension */ + str = "Plain Text Extension"; + break; + case 0xff: /* Application Extension */ + str = "Application Extension"; + break; + case 0xfe: /* Comment Extension */ + str = "Comment Extension"; + while (GetDataBlock(src, (unsigned char *) buf) != 0) + ; + return FALSE; + case 0xf9: /* Graphic Control Extension */ + str = "Graphic Control Extension"; + (void) GetDataBlock(src, (unsigned char *) buf); + Gif89.disposal = (buf[0] >> 2) & 0x7; + Gif89.inputFlag = (buf[0] >> 1) & 0x1; + Gif89.delayTime = LM_to_uint(buf[1], buf[2]); + if ((buf[0] & 0x1) != 0) + Gif89.transparent = buf[3]; + + while (GetDataBlock(src, (unsigned char *) buf) != 0) + ; + return FALSE; + default: + str = (char *)buf; + sprintf(str, "UNKNOWN (0x%02x)", label); + break; + } + + while (GetDataBlock(src, (unsigned char *) buf) != 0) + ; + + return FALSE; +} + +static int ZeroDataBlock = FALSE; + +static int +GetDataBlock(SDL_RWops *src, unsigned char *buf) +{ + unsigned char count; + + if (!ReadOK(src, &count, 1)) { + /* pm_message("error in getting DataBlock size" ); */ + return -1; + } + ZeroDataBlock = count == 0; + + if ((count != 0) && (!ReadOK(src, buf, count))) { + /* pm_message("error in reading DataBlock" ); */ + return -1; + } + return count; +} + +static int +GetCode(SDL_RWops *src, int code_size, int flag) +{ + static unsigned char buf[280]; + static int curbit, lastbit, done, last_byte; + int i, j, ret; + unsigned char count; + + if (flag) { + curbit = 0; + lastbit = 0; + done = FALSE; + return 0; + } + if ((curbit + code_size) >= lastbit) { + if (done) { + if (curbit >= lastbit) + RWSetMsg("ran off the end of my bits"); + return -1; + } + buf[0] = buf[last_byte - 2]; + buf[1] = buf[last_byte - 1]; + + if ((count = GetDataBlock(src, &buf[2])) == 0) + done = TRUE; + + last_byte = 2 + count; + curbit = (curbit - lastbit) + 16; + lastbit = (2 + count) * 8; + } + ret = 0; + for (i = curbit, j = 0; j < code_size; ++i, ++j) + ret |= ((buf[i / 8] & (1 << (i % 8))) != 0) << j; + + curbit += code_size; + + return ret; +} + +static int +LWZReadByte(SDL_RWops *src, int flag, int input_code_size) +{ + static int fresh = FALSE; + int code, incode; + static int code_size, set_code_size; + static int max_code, max_code_size; + static int firstcode, oldcode; + static int clear_code, end_code; + static int table[2][(1 << MAX_LWZ_BITS)]; + static int stack[(1 << (MAX_LWZ_BITS)) * 2], *sp; + register int i; + + /* Fixed buffer overflow found by Michael Skladnikiewicz */ + if (input_code_size > MAX_LWZ_BITS) + return -1; + + if (flag) { + set_code_size = input_code_size; + code_size = set_code_size + 1; + clear_code = 1 << set_code_size; + end_code = clear_code + 1; + max_code_size = 2 * clear_code; + max_code = clear_code + 2; + + GetCode(src, 0, TRUE); + + fresh = TRUE; + + for (i = 0; i < clear_code; ++i) { + table[0][i] = 0; + table[1][i] = i; + } + for (; i < (1 << MAX_LWZ_BITS); ++i) + table[0][i] = table[1][0] = 0; + + sp = stack; + + return 0; + } else if (fresh) { + fresh = FALSE; + do { + firstcode = oldcode = GetCode(src, code_size, FALSE); + } while (firstcode == clear_code); + return firstcode; + } + if (sp > stack) + return *--sp; + + while ((code = GetCode(src, code_size, FALSE)) >= 0) { + if (code == clear_code) { + for (i = 0; i < clear_code; ++i) { + table[0][i] = 0; + table[1][i] = i; + } + for (; i < (1 << MAX_LWZ_BITS); ++i) + table[0][i] = table[1][i] = 0; + code_size = set_code_size + 1; + max_code_size = 2 * clear_code; + max_code = clear_code + 2; + sp = stack; + firstcode = oldcode = GetCode(src, code_size, FALSE); + return firstcode; + } else if (code == end_code) { + int count; + unsigned char buf[260]; + + if (ZeroDataBlock) + return -2; + + while ((count = GetDataBlock(src, buf)) > 0) + ; + + if (count != 0) { + /* + * pm_message("missing EOD in data stream (common occurence)"); + */ + } + return -2; + } + incode = code; + + if (code >= max_code) { + *sp++ = firstcode; + code = oldcode; + } + while (code >= clear_code) { + *sp++ = table[1][code]; + if (code == table[0][code]) + RWSetMsg("circular table entry BIG ERROR"); + code = table[0][code]; + } + + *sp++ = firstcode = table[1][code]; + + if ((code = max_code) < (1 << MAX_LWZ_BITS)) { + table[0][code] = oldcode; + table[1][code] = firstcode; + ++max_code; + if ((max_code >= max_code_size) && + (max_code_size < (1 << MAX_LWZ_BITS))) { + max_code_size *= 2; + ++code_size; + } + } + oldcode = incode; + + if (sp > stack) + return *--sp; + } + return code; +} + +static Image * +ReadImage(SDL_RWops * src, int len, int height, int cmapSize, + unsigned char cmap[3][MAXCOLORMAPSIZE], + int gray, int interlace, int ignore) +{ + Image *image; + unsigned char c; + int i, v; + int xpos = 0, ypos = 0, pass = 0; + + /* + ** Initialize the compression routines + */ + if (!ReadOK(src, &c, 1)) { + RWSetMsg("EOF / read error on image data"); + return NULL; + } + if (LWZReadByte(src, TRUE, c) < 0) { + RWSetMsg("error reading image"); + return NULL; + } + /* + ** If this is an "uninteresting picture" ignore it. + */ + if (ignore) { + while (LWZReadByte(src, FALSE, c) >= 0) + ; + return NULL; + } + image = ImageNewCmap(len, height, cmapSize); + + for (i = 0; i < cmapSize; i++) + ImageSetCmap(image, i, cmap[CM_RED][i], + cmap[CM_GREEN][i], cmap[CM_BLUE][i]); + + while ((v = LWZReadByte(src, FALSE, c)) >= 0) { +#ifdef USED_BY_SDL + ((Uint8 *)image->pixels)[xpos + ypos * image->pitch] = v; +#else + image->data[xpos + ypos * len] = v; +#endif + ++xpos; + if (xpos == len) { + xpos = 0; + if (interlace) { + switch (pass) { + case 0: + case 1: + ypos += 8; + break; + case 2: + ypos += 4; + break; + case 3: + ypos += 2; + break; + } + + if (ypos >= height) { + ++pass; + switch (pass) { + case 1: + ypos = 4; + break; + case 2: + ypos = 2; + break; + case 3: + ypos = 1; + break; + default: + goto fini; + } + } + } else { + ++ypos; + } + } + if (ypos >= height) + break; + } + + fini: + + return image; +} + +#else + +/* See if an image is contained in a data source */ +int IMG_isGIF(SDL_RWops *src) +{ + return(0); +} + +/* Load a GIF type image from an SDL datasource */ +SDL_Surface *IMG_LoadGIF_RW(SDL_RWops *src) +{ + return(NULL); +} + +#endif /* LOAD_GIF */ + +#endif /* !defined(__APPLE__) || defined(SDL_IMAGE_USE_COMMON_BACKEND) */ diff --git a/engines/vileVN/external/SDL/image/IMG_jpg.c b/engines/vileVN/external/SDL/image/IMG_jpg.c new file mode 100644 index 0000000000..7484ab1bbb --- /dev/null +++ b/engines/vileVN/external/SDL/image/IMG_jpg.c @@ -0,0 +1,495 @@ +/* + SDL_image: An example image loading library for use with SDL + Copyright (C) 1997-2012 Sam Lantinga + + 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. +*/ + +#if !defined(__APPLE__) || defined(SDL_IMAGE_USE_COMMON_BACKEND) + +/* This is a JPEG image file loading framework */ + +#include +#include +#include + +#include "SDL_image.h" + +#ifdef LOAD_JPG + +#include + +#ifdef JPEG_TRUE /* MinGW version of jpeg-8.x renamed TRUE to JPEG_TRUE etc. */ + typedef JPEG_boolean boolean; + #define TRUE JPEG_TRUE + #define FALSE JPEG_FALSE +#endif + +/* Define this for fast loading and not as good image quality */ +/*#define FAST_JPEG*/ + +/* Define this for quicker (but less perfect) JPEG identification */ +#define FAST_IS_JPEG + +static struct { + int loaded; + void *handle; + void (*jpeg_calc_output_dimensions) (j_decompress_ptr cinfo); + void (*jpeg_CreateDecompress) (j_decompress_ptr cinfo, int version, size_t structsize); + void (*jpeg_destroy_decompress) (j_decompress_ptr cinfo); + boolean (*jpeg_finish_decompress) (j_decompress_ptr cinfo); + int (*jpeg_read_header) (j_decompress_ptr cinfo, boolean require_image); + JDIMENSION (*jpeg_read_scanlines) (j_decompress_ptr cinfo, JSAMPARRAY scanlines, JDIMENSION max_lines); + boolean (*jpeg_resync_to_restart) (j_decompress_ptr cinfo, int desired); + boolean (*jpeg_start_decompress) (j_decompress_ptr cinfo); + struct jpeg_error_mgr * (*jpeg_std_error) (struct jpeg_error_mgr * err); +} lib; + +#ifdef LOAD_JPG_DYNAMIC +int IMG_InitJPG() +{ + if ( lib.loaded == 0 ) { + lib.handle = SDL_LoadObject(LOAD_JPG_DYNAMIC); + if ( lib.handle == NULL ) { + return -1; + } + lib.jpeg_calc_output_dimensions = + (void (*) (j_decompress_ptr)) + SDL_LoadFunction(lib.handle, "jpeg_calc_output_dimensions"); + if ( lib.jpeg_calc_output_dimensions == NULL ) { + SDL_UnloadObject(lib.handle); + return -1; + } + lib.jpeg_CreateDecompress = + (void (*) (j_decompress_ptr, int, size_t)) + SDL_LoadFunction(lib.handle, "jpeg_CreateDecompress"); + if ( lib.jpeg_CreateDecompress == NULL ) { + SDL_UnloadObject(lib.handle); + return -1; + } + lib.jpeg_destroy_decompress = + (void (*) (j_decompress_ptr)) + SDL_LoadFunction(lib.handle, "jpeg_destroy_decompress"); + if ( lib.jpeg_destroy_decompress == NULL ) { + SDL_UnloadObject(lib.handle); + return -1; + } + lib.jpeg_finish_decompress = + (boolean (*) (j_decompress_ptr)) + SDL_LoadFunction(lib.handle, "jpeg_finish_decompress"); + if ( lib.jpeg_finish_decompress == NULL ) { + SDL_UnloadObject(lib.handle); + return -1; + } + lib.jpeg_read_header = + (int (*) (j_decompress_ptr, boolean)) + SDL_LoadFunction(lib.handle, "jpeg_read_header"); + if ( lib.jpeg_read_header == NULL ) { + SDL_UnloadObject(lib.handle); + return -1; + } + lib.jpeg_read_scanlines = + (JDIMENSION (*) (j_decompress_ptr, JSAMPARRAY, JDIMENSION)) + SDL_LoadFunction(lib.handle, "jpeg_read_scanlines"); + if ( lib.jpeg_read_scanlines == NULL ) { + SDL_UnloadObject(lib.handle); + return -1; + } + lib.jpeg_resync_to_restart = + (boolean (*) (j_decompress_ptr, int)) + SDL_LoadFunction(lib.handle, "jpeg_resync_to_restart"); + if ( lib.jpeg_resync_to_restart == NULL ) { + SDL_UnloadObject(lib.handle); + return -1; + } + lib.jpeg_start_decompress = + (boolean (*) (j_decompress_ptr)) + SDL_LoadFunction(lib.handle, "jpeg_start_decompress"); + if ( lib.jpeg_start_decompress == NULL ) { + SDL_UnloadObject(lib.handle); + return -1; + } + lib.jpeg_std_error = + (struct jpeg_error_mgr * (*) (struct jpeg_error_mgr *)) + SDL_LoadFunction(lib.handle, "jpeg_std_error"); + if ( lib.jpeg_std_error == NULL ) { + SDL_UnloadObject(lib.handle); + return -1; + } + } + ++lib.loaded; + + return 0; +} +void IMG_QuitJPG() +{ + if ( lib.loaded == 0 ) { + return; + } + if ( lib.loaded == 1 ) { + SDL_UnloadObject(lib.handle); + } + --lib.loaded; +} +#else +int IMG_InitJPG() +{ + if ( lib.loaded == 0 ) { + lib.jpeg_calc_output_dimensions = jpeg_calc_output_dimensions; + lib.jpeg_CreateDecompress = jpeg_CreateDecompress; + lib.jpeg_destroy_decompress = jpeg_destroy_decompress; + lib.jpeg_finish_decompress = jpeg_finish_decompress; + lib.jpeg_read_header = jpeg_read_header; + lib.jpeg_read_scanlines = jpeg_read_scanlines; + lib.jpeg_resync_to_restart = jpeg_resync_to_restart; + lib.jpeg_start_decompress = jpeg_start_decompress; + lib.jpeg_std_error = jpeg_std_error; + } + ++lib.loaded; + + return 0; +} +void IMG_QuitJPG() +{ + if ( lib.loaded == 0 ) { + return; + } + if ( lib.loaded == 1 ) { + } + --lib.loaded; +} +#endif /* LOAD_JPG_DYNAMIC */ + +/* See if an image is contained in a data source */ +int IMG_isJPG(SDL_RWops *src) +{ + int start; + int is_JPG; + int in_scan; + Uint8 magic[4]; + + /* This detection code is by Steaphan Greene */ + /* Blame me, not Sam, if this doesn't work right. */ + /* And don't forget to report the problem to the the sdl list too! */ + + if ( !src ) + return 0; + start = SDL_RWtell(src); + is_JPG = 0; + in_scan = 0; + if ( SDL_RWread(src, magic, 2, 1) ) { + if ( (magic[0] == 0xFF) && (magic[1] == 0xD8) ) { + is_JPG = 1; + while (is_JPG == 1) { + if(SDL_RWread(src, magic, 1, 2) != 2) { + is_JPG = 0; + } else if( (magic[0] != 0xFF) && (in_scan == 0) ) { + is_JPG = 0; + } else if( (magic[0] != 0xFF) || (magic[1] == 0xFF) ) { + /* Extra padding in JPEG (legal) */ + /* or this is data and we are scanning */ + SDL_RWseek(src, -1, RW_SEEK_CUR); + } else if(magic[1] == 0xD9) { + /* Got to end of good JPEG */ + break; + } else if( (in_scan == 1) && (magic[1] == 0x00) ) { + /* This is an encoded 0xFF within the data */ + } else if( (magic[1] >= 0xD0) && (magic[1] < 0xD9) ) { + /* These have nothing else */ + } else if(SDL_RWread(src, magic+2, 1, 2) != 2) { + is_JPG = 0; + } else { + /* Yes, it's big-endian */ + Uint32 start; + Uint32 size; + Uint32 end; + start = SDL_RWtell(src); + size = (magic[2] << 8) + magic[3]; + end = SDL_RWseek(src, size-2, RW_SEEK_CUR); + if ( end != start + size - 2 ) is_JPG = 0; + if ( magic[1] == 0xDA ) { + /* Now comes the actual JPEG meat */ +#ifdef FAST_IS_JPEG + /* Ok, I'm convinced. It is a JPEG. */ + break; +#else + /* I'm not convinced. Prove it! */ + in_scan = 1; +#endif + } + } + } + } + } + SDL_RWseek(src, start, RW_SEEK_SET); + return(is_JPG); +} + +#define INPUT_BUFFER_SIZE 4096 +typedef struct { + struct jpeg_source_mgr pub; + + SDL_RWops *ctx; + Uint8 buffer[INPUT_BUFFER_SIZE]; +} my_source_mgr; + +/* + * Initialize source --- called by jpeg_read_header + * before any data is actually read. + */ +static void init_source (j_decompress_ptr cinfo) +{ + /* We don't actually need to do anything */ + return; +} + +/* + * Fill the input buffer --- called whenever buffer is emptied. + */ +static boolean fill_input_buffer (j_decompress_ptr cinfo) +{ + my_source_mgr * src = (my_source_mgr *) cinfo->src; + int nbytes; + + nbytes = SDL_RWread(src->ctx, src->buffer, 1, INPUT_BUFFER_SIZE); + if (nbytes <= 0) { + /* Insert a fake EOI marker */ + src->buffer[0] = (Uint8) 0xFF; + src->buffer[1] = (Uint8) JPEG_EOI; + nbytes = 2; + } + src->pub.next_input_byte = src->buffer; + src->pub.bytes_in_buffer = nbytes; + + 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. + */ +static void skip_input_data (j_decompress_ptr cinfo, long num_bytes) +{ + my_source_mgr * src = (my_source_mgr *) cinfo->src; + + /* Just a dumb implementation for now. Could use fseek() except + * it doesn't work on pipes. Not clear that being smart is worth + * any trouble anyway --- large skips are infrequent. + */ + if (num_bytes > 0) { + while (num_bytes > (long) src->pub.bytes_in_buffer) { + num_bytes -= (long) src->pub.bytes_in_buffer; + (void) src->pub.fill_input_buffer(cinfo); + /* note we assume that fill_input_buffer will never + * return FALSE, so suspension need not be handled. + */ + } + src->pub.next_input_byte += (size_t) num_bytes; + src->pub.bytes_in_buffer -= (size_t) num_bytes; + } +} + +/* + * Terminate source --- called by jpeg_finish_decompress + * after all data has been read. + */ +static void term_source (j_decompress_ptr cinfo) +{ + /* We don't actually need to do anything */ + return; +} + +/* + * Prepare for input from a stdio stream. + * The caller must have already opened the stream, and is responsible + * for closing it after finishing decompression. + */ +static void jpeg_SDL_RW_src (j_decompress_ptr cinfo, SDL_RWops *ctx) +{ + my_source_mgr *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_source_mgr *) cinfo->src; + } + + src = (my_source_mgr *) 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 = lib.jpeg_resync_to_restart; /* use default method */ + src->pub.term_source = term_source; + src->ctx = ctx; + src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */ + src->pub.next_input_byte = NULL; /* until buffer loaded */ +} + +struct my_error_mgr { + struct jpeg_error_mgr errmgr; + jmp_buf escape; +}; + +static void my_error_exit(j_common_ptr cinfo) +{ + struct my_error_mgr *err = (struct my_error_mgr *)cinfo->err; + longjmp(err->escape, 1); +} + +static void output_no_message(j_common_ptr cinfo) +{ + /* do nothing */ +} + +/* Load a JPEG type image from an SDL datasource */ +SDL_Surface *IMG_LoadJPG_RW(SDL_RWops *src) +{ + int start; + struct jpeg_decompress_struct cinfo; + JSAMPROW rowptr[1]; + SDL_Surface *volatile surface = NULL; + struct my_error_mgr jerr; + + if ( !src ) { + /* The error message has been set in SDL_RWFromFile */ + return NULL; + } + start = SDL_RWtell(src); + + if ( !IMG_Init(IMG_INIT_JPG) ) { + return NULL; + } + + /* Create a decompression structure and load the JPEG header */ + cinfo.err = lib.jpeg_std_error(&jerr.errmgr); + jerr.errmgr.error_exit = my_error_exit; + jerr.errmgr.output_message = output_no_message; + if(setjmp(jerr.escape)) { + /* If we get here, libjpeg found an error */ + lib.jpeg_destroy_decompress(&cinfo); + if ( surface != NULL ) { + SDL_FreeSurface(surface); + } + SDL_RWseek(src, start, RW_SEEK_SET); + IMG_SetError("JPEG loading error"); + return NULL; + } + + lib.jpeg_create_decompress(&cinfo); + jpeg_SDL_RW_src(&cinfo, src); + lib.jpeg_read_header(&cinfo, TRUE); + + if(cinfo.num_components == 4) { + /* Set 32-bit Raw output */ + cinfo.out_color_space = JCS_CMYK; + cinfo.quantize_colors = FALSE; + lib.jpeg_calc_output_dimensions(&cinfo); + + /* Allocate an output surface to hold the image */ + surface = SDL_AllocSurface(SDL_SWSURFACE, + cinfo.output_width, cinfo.output_height, 32, +#if SDL_BYTEORDER == SDL_LIL_ENDIAN + 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000); +#else + 0x0000FF00, 0x00FF0000, 0xFF000000, 0x000000FF); +#endif + } else { + /* Set 24-bit RGB output */ + cinfo.out_color_space = JCS_RGB; + cinfo.quantize_colors = FALSE; +#ifdef FAST_JPEG + cinfo.scale_num = 1; + cinfo.scale_denom = 1; + cinfo.dct_method = JDCT_FASTEST; + cinfo.do_fancy_upsampling = FALSE; +#endif + lib.jpeg_calc_output_dimensions(&cinfo); + + /* Allocate an output surface to hold the image */ + surface = SDL_AllocSurface(SDL_SWSURFACE, + cinfo.output_width, cinfo.output_height, 24, +#if SDL_BYTEORDER == SDL_LIL_ENDIAN + 0x0000FF, 0x00FF00, 0xFF0000, +#else + 0xFF0000, 0x00FF00, 0x0000FF, +#endif + 0); + } + + if ( surface == NULL ) { + lib.jpeg_destroy_decompress(&cinfo); + SDL_RWseek(src, start, RW_SEEK_SET); + IMG_SetError("Out of memory"); + return NULL; + } + + /* Decompress the image */ + lib.jpeg_start_decompress(&cinfo); + while ( cinfo.output_scanline < cinfo.output_height ) { + rowptr[0] = (JSAMPROW)(Uint8 *)surface->pixels + + cinfo.output_scanline * surface->pitch; + lib.jpeg_read_scanlines(&cinfo, rowptr, (JDIMENSION) 1); + } + lib.jpeg_finish_decompress(&cinfo); + lib.jpeg_destroy_decompress(&cinfo); + + return(surface); +} + +#else + +int IMG_InitJPG() +{ + IMG_SetError("JPEG images are not supported"); + return(-1); +} + +void IMG_QuitJPG() +{ +} + +/* See if an image is contained in a data source */ +int IMG_isJPG(SDL_RWops *src) +{ + return(0); +} + +/* Load a JPEG type image from an SDL datasource */ +SDL_Surface *IMG_LoadJPG_RW(SDL_RWops *src) +{ + return(NULL); +} + +#endif /* LOAD_JPG */ + +#endif /* !defined(__APPLE__) || defined(SDL_IMAGE_USE_COMMON_BACKEND) */ diff --git a/engines/vileVN/external/SDL/image/IMG_lbm.c b/engines/vileVN/external/SDL/image/IMG_lbm.c new file mode 100644 index 0000000000..f475c60cf9 --- /dev/null +++ b/engines/vileVN/external/SDL/image/IMG_lbm.c @@ -0,0 +1,503 @@ +/* + SDL_image: An example image loading library for use with SDL + Copyright (C) 1997-2012 Sam Lantinga + + 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. +*/ + +/* This is a ILBM image file loading framework + Load IFF pictures, PBM & ILBM packing methods, with or without stencil + Written by Daniel Morais ( Daniel AT Morais DOT com ) in September 2001. + 24 bits ILBM files support added by Marc Le Douarain (http://www.multimania.com/mavati) + in December 2002. + EHB and HAM (specific Amiga graphic chip modes) support added by Marc Le Douarain + (http://www.multimania.com/mavati) in December 2003. + Stencil and colorkey fixes by David Raulo (david.raulo AT free DOT fr) in February 2004. + Buffer overflow fix in RLE decompression by David Raulo in January 2008. +*/ + +#include +#include +#include + +#include "SDL_endian.h" +#include "SDL_image.h" + +#ifdef LOAD_LBM + + +#define MAXCOLORS 256 + +/* Structure for an IFF picture ( BMHD = Bitmap Header ) */ + +typedef struct +{ + Uint16 w, h; /* width & height of the bitmap in pixels */ + Sint16 x, y; /* screen coordinates of the bitmap */ + Uint8 planes; /* number of planes of the bitmap */ + Uint8 mask; /* mask type ( 0 => no mask ) */ + Uint8 tcomp; /* compression type */ + Uint8 pad1; /* dummy value, for padding */ + Uint16 tcolor; /* transparent color */ + Uint8 xAspect, /* pixel aspect ratio */ + yAspect; + Sint16 Lpage; /* width of the screen in pixels */ + Sint16 Hpage; /* height of the screen in pixels */ +} BMHD; + +int IMG_isLBM( SDL_RWops *src ) +{ + int start; + int is_LBM; + Uint8 magic[4+4+4]; + + if ( !src ) + return 0; + start = SDL_RWtell(src); + is_LBM = 0; + if ( SDL_RWread( src, magic, sizeof(magic), 1 ) ) + { + if ( !memcmp( magic, "FORM", 4 ) && + ( !memcmp( magic + 8, "PBM ", 4 ) || + !memcmp( magic + 8, "ILBM", 4 ) ) ) + { + is_LBM = 1; + } + } + SDL_RWseek(src, start, RW_SEEK_SET); + return( is_LBM ); +} + +SDL_Surface *IMG_LoadLBM_RW( SDL_RWops *src ) +{ + int start; + SDL_Surface *Image; + Uint8 id[4], pbm, colormap[MAXCOLORS*3], *MiniBuf, *ptr, count, color, msk; + Uint32 size, bytesloaded, nbcolors; + Uint32 i, j, bytesperline, nbplanes, stencil, plane, h; + Uint32 remainingbytes; + Uint32 width; + BMHD bmhd; + char *error; + Uint8 flagHAM,flagEHB; + + Image = NULL; + error = NULL; + MiniBuf = NULL; + + if ( !src ) { + /* The error message has been set in SDL_RWFromFile */ + return NULL; + } + start = SDL_RWtell(src); + + if ( !SDL_RWread( src, id, 4, 1 ) ) + { + error="error reading IFF chunk"; + goto done; + } + + /* Should be the size of the file minus 4+4 ( 'FORM'+size ) */ + if ( !SDL_RWread( src, &size, 4, 1 ) ) + { + error="error reading IFF chunk size"; + goto done; + } + + /* As size is not used here, no need to swap it */ + + if ( memcmp( id, "FORM", 4 ) != 0 ) + { + error="not a IFF file"; + goto done; + } + + if ( !SDL_RWread( src, id, 4, 1 ) ) + { + error="error reading IFF chunk"; + goto done; + } + + pbm = 0; + + /* File format : PBM=Packed Bitmap, ILBM=Interleaved Bitmap */ + if ( !memcmp( id, "PBM ", 4 ) ) pbm = 1; + else if ( memcmp( id, "ILBM", 4 ) ) + { + error="not a IFF picture"; + goto done; + } + + nbcolors = 0; + + memset( &bmhd, 0, sizeof( BMHD ) ); + flagHAM = 0; + flagEHB = 0; + + while ( memcmp( id, "BODY", 4 ) != 0 ) + { + if ( !SDL_RWread( src, id, 4, 1 ) ) + { + error="error reading IFF chunk"; + goto done; + } + + if ( !SDL_RWread( src, &size, 4, 1 ) ) + { + error="error reading IFF chunk size"; + goto done; + } + + bytesloaded = 0; + + size = SDL_SwapBE32( size ); + + if ( !memcmp( id, "BMHD", 4 ) ) /* Bitmap header */ + { + if ( !SDL_RWread( src, &bmhd, sizeof( BMHD ), 1 ) ) + { + error="error reading BMHD chunk"; + goto done; + } + + bytesloaded = sizeof( BMHD ); + + bmhd.w = SDL_SwapBE16( bmhd.w ); + bmhd.h = SDL_SwapBE16( bmhd.h ); + bmhd.x = SDL_SwapBE16( bmhd.x ); + bmhd.y = SDL_SwapBE16( bmhd.y ); + bmhd.tcolor = SDL_SwapBE16( bmhd.tcolor ); + bmhd.Lpage = SDL_SwapBE16( bmhd.Lpage ); + bmhd.Hpage = SDL_SwapBE16( bmhd.Hpage ); + } + + if ( !memcmp( id, "CMAP", 4 ) ) /* palette ( Color Map ) */ + { + if ( !SDL_RWread( src, &colormap, size, 1 ) ) + { + error="error reading CMAP chunk"; + goto done; + } + + bytesloaded = size; + nbcolors = size / 3; + } + + if ( !memcmp( id, "CAMG", 4 ) ) /* Amiga ViewMode */ + { + Uint32 viewmodes; + if ( !SDL_RWread( src, &viewmodes, sizeof(viewmodes), 1 ) ) + { + error="error reading CAMG chunk"; + goto done; + } + + bytesloaded = size; + viewmodes = SDL_SwapBE32( viewmodes ); + if ( viewmodes & 0x0800 ) + flagHAM = 1; + if ( viewmodes & 0x0080 ) + flagEHB = 1; + } + + if ( memcmp( id, "BODY", 4 ) ) + { + if ( size & 1 ) ++size; /* padding ! */ + size -= bytesloaded; + /* skip the remaining bytes of this chunk */ + if ( size ) SDL_RWseek( src, size, RW_SEEK_CUR ); + } + } + + /* compute some usefull values, based on the bitmap header */ + + width = ( bmhd.w + 15 ) & 0xFFFFFFF0; /* Width in pixels modulo 16 */ + + bytesperline = ( ( bmhd.w + 15 ) / 16 ) * 2; + + nbplanes = bmhd.planes; + + if ( pbm ) /* File format : 'Packed Bitmap' */ + { + bytesperline *= 8; + nbplanes = 1; + } + + stencil = (bmhd.mask & 1); /* There is a mask ( 'stencil' ) */ + + /* Allocate memory for a temporary buffer ( used for + decompression/deinterleaving ) */ + + MiniBuf = (void *)malloc( bytesperline * (nbplanes + stencil) ); + if ( MiniBuf == NULL ) + { + error="no enough memory for temporary buffer"; + goto done; + } + + if ( ( Image = SDL_CreateRGBSurface( SDL_SWSURFACE, width, bmhd.h, (bmhd.planes==24 || flagHAM==1)?24:8, 0, 0, 0, 0 ) ) == NULL ) + goto done; + + if ( bmhd.mask & 2 ) /* There is a transparent color */ + SDL_SetColorKey( Image, SDL_SRCCOLORKEY, bmhd.tcolor ); + + /* Update palette informations */ + + /* There is no palette in 24 bits ILBM file */ + if ( nbcolors>0 && flagHAM==0 ) + { + /* FIXME: Should this include the stencil? See comment below */ + int nbrcolorsfinal = 1 << (nbplanes + stencil); + ptr = &colormap[0]; + + for ( i=0; iformat->palette->colors[i].r = *ptr++; + Image->format->palette->colors[i].g = *ptr++; + Image->format->palette->colors[i].b = *ptr++; + } + + /* Amiga EHB mode (Extra-Half-Bright) */ + /* 6 bitplanes mode with a 32 colors palette */ + /* The 32 last colors are the same but divided by 2 */ + /* Some Amiga pictures save 64 colors with 32 last wrong colors, */ + /* they shouldn't !, and here we overwrite these 32 bad colors. */ + if ( (nbcolors==32 || flagEHB ) && (1<format->palette->colors[i].r = (*ptr++)/2; + Image->format->palette->colors[i].g = (*ptr++)/2; + Image->format->palette->colors[i].b = (*ptr++)/2; + } + } + + /* If nbcolors < 2^nbplanes, repeat the colormap */ + /* This happens when pictures have a stencil mask */ + if ( nbrcolorsfinal > (1<format->palette->colors[i].r = Image->format->palette->colors[i%nbcolors].r; + Image->format->palette->colors[i].g = Image->format->palette->colors[i%nbcolors].g; + Image->format->palette->colors[i].b = Image->format->palette->colors[i%nbcolors].b; + } + if ( !pbm ) + Image->format->palette->ncolors = nbrcolorsfinal; + } + + /* Get the bitmap */ + + for ( h=0; h < bmhd.h; h++ ) + { + /* uncompress the datas of each planes */ + + for ( plane=0; plane < (nbplanes+stencil); plane++ ) + { + ptr = MiniBuf + ( plane * bytesperline ); + + remainingbytes = bytesperline; + + if ( bmhd.tcomp == 1 ) /* Datas are compressed */ + { + do + { + if ( !SDL_RWread( src, &count, 1, 1 ) ) + { + error="error reading BODY chunk"; + goto done; + } + + if ( count & 0x80 ) + { + count ^= 0xFF; + count += 2; /* now it */ + + if ( ( count > remainingbytes ) || !SDL_RWread( src, &color, 1, 1 ) ) + { + error="error reading BODY chunk"; + goto done; + } + memset( ptr, color, count ); + } + else + { + ++count; + + if ( ( count > remainingbytes ) || !SDL_RWread( src, ptr, count, 1 ) ) + { + error="error reading BODY chunk"; + goto done; + } + } + + ptr += count; + remainingbytes -= count; + + } while ( remainingbytes > 0 ); + } + else + { + if ( !SDL_RWread( src, ptr, bytesperline, 1 ) ) + { + error="error reading BODY chunk"; + goto done; + } + } + } + + /* One line has been read, store it ! */ + + ptr = Image->pixels; + if ( nbplanes==24 || flagHAM==1 ) + ptr += h * width * 3; + else + ptr += h * width; + + if ( pbm ) /* File format : 'Packed Bitmap' */ + { + memcpy( ptr, MiniBuf, width ); + } + else /* We have to un-interlace the bits ! */ + { + if ( nbplanes!=24 && flagHAM==0 ) + { + size = ( width + 7 ) / 8; + + for ( i=0; i < size; i++ ) + { + memset( ptr, 0, 8 ); + + for ( plane=0; plane < (nbplanes + stencil); plane++ ) + { + color = *( MiniBuf + i + ( plane * bytesperline ) ); + msk = 0x80; + + for ( j=0; j<8; j++ ) + { + if ( ( plane + j ) <= 7 ) ptr[j] |= (Uint8)( color & msk ) >> ( 7 - plane - j ); + else ptr[j] |= (Uint8)( color & msk ) << ( plane + j - 7 ); + + msk >>= 1; + } + } + ptr += 8; + } + } + else + { + Uint32 finalcolor = 0; + size = ( width + 7 ) / 8; + /* 24 bitplanes ILBM : R0...R7,G0...G7,B0...B7 */ + /* or HAM (6 bitplanes) or HAM8 (8 bitplanes) modes */ + for ( i=0; i>(nbplanes-2) ) + { + case 0: /* take direct color from palette */ + finalcolor = colormap[ pixelcolor*3 ] + (colormap[ pixelcolor*3+1 ]<<8) + (colormap[ pixelcolor*3+2 ]<<16); + break; + case 1: /* modify only blue component */ + finalcolor = finalcolor&0x00FFFF; + finalcolor = finalcolor | (pixelcolor<<(16+(10-nbplanes))); + break; + case 2: /* modify only red component */ + finalcolor = finalcolor&0xFFFF00; + finalcolor = finalcolor | pixelcolor<<(10-nbplanes); + break; + case 3: /* modify only green component */ + finalcolor = finalcolor&0xFF00FF; + finalcolor = finalcolor | (pixelcolor<<(8+(10-nbplanes))); + break; + } + } + else + { + finalcolor = pixelcolor; + } + if ( SDL_BYTEORDER == SDL_LIL_ENDIAN ) + { + *ptr++ = (Uint8)(finalcolor>>16); + *ptr++ = (Uint8)(finalcolor>>8); + *ptr++ = (Uint8)(finalcolor); + } + else + { + *ptr++ = (Uint8)(finalcolor); + *ptr++ = (Uint8)(finalcolor>>8); + *ptr++ = (Uint8)(finalcolor>>16); + } + + maskBit = maskBit>>1; + } + } + } + } + } + +done: + + if ( MiniBuf ) free( MiniBuf ); + + if ( error ) + { + SDL_RWseek(src, start, RW_SEEK_SET); + if ( Image ) { + SDL_FreeSurface( Image ); + Image = NULL; + } + IMG_SetError( error ); + } + + return( Image ); +} + +#else /* LOAD_LBM */ + +/* See if an image is contained in a data source */ +int IMG_isLBM(SDL_RWops *src) +{ + return(0); +} + +/* Load an IFF type image from an SDL datasource */ +SDL_Surface *IMG_LoadLBM_RW(SDL_RWops *src) +{ + return(NULL); +} + +#endif /* LOAD_LBM */ diff --git a/engines/vileVN/external/SDL/image/IMG_pcx.c b/engines/vileVN/external/SDL/image/IMG_pcx.c new file mode 100644 index 0000000000..f62eac1268 --- /dev/null +++ b/engines/vileVN/external/SDL/image/IMG_pcx.c @@ -0,0 +1,276 @@ +/* + SDL_image: An example image loading library for use with SDL + Copyright (C) 1997-2012 Sam Lantinga + + 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. +*/ + +/* + * PCX file reader: + * Supports: + * 1..4 bits/pixel in multiplanar format (1 bit/plane/pixel) + * 8 bits/pixel in single-planar format (8 bits/plane/pixel) + * 24 bits/pixel in 3-plane format (8 bits/plane/pixel) + * + * (The <8bpp formats are expanded to 8bpp surfaces) + * + * Doesn't support: + * single-planar packed-pixel formats other than 8bpp + * 4-plane 32bpp format with a fourth "intensity" plane + */ +#include +#include + +#include "SDL_endian.h" + +#include "SDL_image.h" + +#ifdef LOAD_PCX + +struct PCXheader { + Uint8 Manufacturer; + Uint8 Version; + Uint8 Encoding; + Uint8 BitsPerPixel; + Sint16 Xmin, Ymin, Xmax, Ymax; + Sint16 HDpi, VDpi; + Uint8 Colormap[48]; + Uint8 Reserved; + Uint8 NPlanes; + Sint16 BytesPerLine; + Sint16 PaletteInfo; + Sint16 HscreenSize; + Sint16 VscreenSize; + Uint8 Filler[54]; +}; + +/* See if an image is contained in a data source */ +int IMG_isPCX(SDL_RWops *src) +{ + int start; + int is_PCX; + const int ZSoft_Manufacturer = 10; + const int PC_Paintbrush_Version = 5; + const int PCX_Uncompressed_Encoding = 0; + const int PCX_RunLength_Encoding = 1; + struct PCXheader pcxh; + + if ( !src ) + return 0; + start = SDL_RWtell(src); + is_PCX = 0; + if ( SDL_RWread(src, &pcxh, sizeof(pcxh), 1) == 1 ) { + if ( (pcxh.Manufacturer == ZSoft_Manufacturer) && + (pcxh.Version == PC_Paintbrush_Version) && + (pcxh.Encoding == PCX_RunLength_Encoding || + pcxh.Encoding == PCX_Uncompressed_Encoding) ) { + is_PCX = 1; + } + } + SDL_RWseek(src, start, RW_SEEK_SET); + return(is_PCX); +} + +/* Load a PCX type image from an SDL datasource */ +SDL_Surface *IMG_LoadPCX_RW(SDL_RWops *src) +{ + int start; + struct PCXheader pcxh; + Uint32 Rmask; + Uint32 Gmask; + Uint32 Bmask; + Uint32 Amask; + SDL_Surface *surface = NULL; + int width, height; + int y, bpl; + Uint8 *row, *buf = NULL; + char *error = NULL; + int bits, src_bits; + + if ( !src ) { + /* The error message has been set in SDL_RWFromFile */ + return NULL; + } + start = SDL_RWtell(src); + + if ( ! SDL_RWread(src, &pcxh, sizeof(pcxh), 1) ) { + error = "file truncated"; + goto done; + } + pcxh.Xmin = SDL_SwapLE16(pcxh.Xmin); + pcxh.Ymin = SDL_SwapLE16(pcxh.Ymin); + pcxh.Xmax = SDL_SwapLE16(pcxh.Xmax); + pcxh.Ymax = SDL_SwapLE16(pcxh.Ymax); + pcxh.BytesPerLine = SDL_SwapLE16(pcxh.BytesPerLine); + + /* Create the surface of the appropriate type */ + width = (pcxh.Xmax - pcxh.Xmin) + 1; + height = (pcxh.Ymax - pcxh.Ymin) + 1; + Rmask = Gmask = Bmask = Amask = 0; + src_bits = pcxh.BitsPerPixel * pcxh.NPlanes; + if((pcxh.BitsPerPixel == 1 && pcxh.NPlanes >= 1 && pcxh.NPlanes <= 4) + || (pcxh.BitsPerPixel == 8 && pcxh.NPlanes == 1)) { + bits = 8; + } else if(pcxh.BitsPerPixel == 8 && pcxh.NPlanes == 3) { + bits = 24; + if ( SDL_BYTEORDER == SDL_LIL_ENDIAN ) { + Rmask = 0x000000FF; + Gmask = 0x0000FF00; + Bmask = 0x00FF0000; + } else { + Rmask = 0xFF0000; + Gmask = 0x00FF00; + Bmask = 0x0000FF; + } + } else { + error = "unsupported PCX format"; + goto done; + } + surface = SDL_AllocSurface(SDL_SWSURFACE, width, height, + bits, Rmask, Gmask, Bmask, Amask); + if ( surface == NULL ) + goto done; + + bpl = pcxh.NPlanes * pcxh.BytesPerLine; + if (bpl > surface->pitch) { + error = "bytes per line is too large (corrupt?)"; + } + buf = malloc(bpl); + row = surface->pixels; + for ( y=0; yh; ++y ) { + /* decode a scan line to a temporary buffer first */ + int i, count = 0; + Uint8 ch; + Uint8 *dst = (src_bits == 8) ? row : buf; + if ( pcxh.Encoding == 0 ) { + if(!SDL_RWread(src, dst, bpl, 1)) { + error = "file truncated"; + goto done; + } + } else { + for(i = 0; i < bpl; i++) { + if(!count) { + if(!SDL_RWread(src, &ch, 1, 1)) { + error = "file truncated"; + goto done; + } + if( (ch & 0xc0) == 0xc0) { + count = ch & 0x3f; + if(!SDL_RWread(src, &ch, 1, 1)) { + error = "file truncated"; + goto done; + } + } else + count = 1; + } + dst[i] = ch; + count--; + } + } + + if(src_bits <= 4) { + /* expand planes to 1 byte/pixel */ + Uint8 *src = buf; + int plane; + for(plane = 0; plane < pcxh.NPlanes; plane++) { + int i, j, x = 0; + for(i = 0; i < pcxh.BytesPerLine; i++) { + Uint8 byte = *src++; + for(j = 7; j >= 0; j--) { + unsigned bit = (byte >> j) & 1; + /* skip padding bits */ + if (i * 8 + j >= width) + continue; + row[x++] |= bit << plane; + } + } + } + } else if(src_bits == 24) { + /* de-interlace planes */ + Uint8 *src = buf; + int plane; + for(plane = 0; plane < pcxh.NPlanes; plane++) { + int x; + dst = row + plane; + for(x = 0; x < width; x++) { + *dst = *src++; + dst += pcxh.NPlanes; + } + } + } + + row += surface->pitch; + } + + if(bits == 8) { + SDL_Color *colors = surface->format->palette->colors; + int nc = 1 << src_bits; + int i; + + surface->format->palette->ncolors = nc; + if(src_bits == 8) { + Uint8 ch; + /* look for a 256-colour palette */ + do { + if ( !SDL_RWread(src, &ch, 1, 1)) { + error = "file truncated"; + goto done; + } + } while ( ch != 12 ); + + for(i = 0; i < 256; i++) { + SDL_RWread(src, &colors[i].r, 1, 1); + SDL_RWread(src, &colors[i].g, 1, 1); + SDL_RWread(src, &colors[i].b, 1, 1); + } + } else { + for(i = 0; i < nc; i++) { + colors[i].r = pcxh.Colormap[i * 3]; + colors[i].g = pcxh.Colormap[i * 3 + 1]; + colors[i].b = pcxh.Colormap[i * 3 + 2]; + } + } + } + +done: + free(buf); + if ( error ) { + SDL_RWseek(src, start, RW_SEEK_SET); + if ( surface ) { + SDL_FreeSurface(surface); + surface = NULL; + } + IMG_SetError(error); + } + return(surface); +} + +#else + +/* See if an image is contained in a data source */ +int IMG_isPCX(SDL_RWops *src) +{ + return(0); +} + +/* Load a PCX type image from an SDL datasource */ +SDL_Surface *IMG_LoadPCX_RW(SDL_RWops *src) +{ + return(NULL); +} + +#endif /* LOAD_PCX */ diff --git a/engines/vileVN/external/SDL/image/IMG_png.c b/engines/vileVN/external/SDL/image/IMG_png.c new file mode 100644 index 0000000000..5f91f156c2 --- /dev/null +++ b/engines/vileVN/external/SDL/image/IMG_png.c @@ -0,0 +1,578 @@ +/* + SDL_image: An example image loading library for use with SDL + Copyright (C) 1997-2012 Sam Lantinga + + 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. +*/ + +#if !defined(__APPLE__) || defined(SDL_IMAGE_USE_COMMON_BACKEND) + +/* This is a PNG image file loading framework */ + +#include +#include + +#include "SDL_image.h" + +#ifdef LOAD_PNG + +/*============================================================================= + File: SDL_png.c + Purpose: A PNG loader and saver for the SDL library + Revision: + Created by: Philippe Lavoie (2 November 1998) + lavoie@zeus.genie.uottawa.ca + Modified by: + + Copyright notice: + Copyright (C) 1998 Philippe Lavoie + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + Comments: The load and save routine are basically the ones you can find + in the example.c file from the libpng distribution. + + Changes: + 5/17/99 - Modified to use the new SDL data sources - Sam Lantinga + +=============================================================================*/ + +#include "SDL_endian.h" + +#ifdef macintosh +#define MACOS +#endif +#include + +/* Check for the older version of libpng */ +#if (PNG_LIBPNG_VER_MAJOR == 1) && (PNG_LIBPNG_VER_MINOR < 4) +#define LIBPNG_VERSION_12 +#endif + +static struct { + int loaded; + void *handle; + png_infop (*png_create_info_struct) (png_structp png_ptr); + png_structp (*png_create_read_struct) (png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn, png_error_ptr warn_fn); + void (*png_destroy_read_struct) (png_structpp png_ptr_ptr, png_infopp info_ptr_ptr, png_infopp end_info_ptr_ptr); + png_uint_32 (*png_get_IHDR) (png_structp png_ptr, png_infop info_ptr, png_uint_32 *width, png_uint_32 *height, int *bit_depth, int *color_type, int *interlace_method, int *compression_method, int *filter_method); + png_voidp (*png_get_io_ptr) (png_structp png_ptr); + png_byte (*png_get_channels) (png_structp png_ptr, png_infop info_ptr); + png_uint_32 (*png_get_PLTE) (png_structp png_ptr, png_infop info_ptr, png_colorp *palette, int *num_palette); + png_uint_32 (*png_get_tRNS) (png_structp png_ptr, png_infop info_ptr, png_bytep *trans, int *num_trans, png_color_16p *trans_values); + png_uint_32 (*png_get_valid) (png_structp png_ptr, png_infop info_ptr, png_uint_32 flag); + void (*png_read_image) (png_structp png_ptr, png_bytepp image); + void (*png_read_info) (png_structp png_ptr, png_infop info_ptr); + void (*png_read_update_info) (png_structp png_ptr, png_infop info_ptr); + void (*png_set_expand) (png_structp png_ptr); + void (*png_set_gray_to_rgb) (png_structp png_ptr); + void (*png_set_packing) (png_structp png_ptr); + void (*png_set_read_fn) (png_structp png_ptr, png_voidp io_ptr, png_rw_ptr read_data_fn); + void (*png_set_strip_16) (png_structp png_ptr); + int (*png_sig_cmp) (png_bytep sig, png_size_t start, png_size_t num_to_check); +#ifndef LIBPNG_VERSION_12 + jmp_buf* (*png_set_longjmp_fn) (png_structp, png_longjmp_ptr, size_t); +#endif +} lib; + +#ifdef LOAD_PNG_DYNAMIC +int IMG_InitPNG() +{ + if ( lib.loaded == 0 ) { + lib.handle = SDL_LoadObject(LOAD_PNG_DYNAMIC); + if ( lib.handle == NULL ) { + return -1; + } + lib.png_create_info_struct = + (png_infop (*) (png_structp)) + SDL_LoadFunction(lib.handle, "png_create_info_struct"); + if ( lib.png_create_info_struct == NULL ) { + SDL_UnloadObject(lib.handle); + return -1; + } + lib.png_create_read_struct = + (png_structp (*) (png_const_charp, png_voidp, png_error_ptr, png_error_ptr)) + SDL_LoadFunction(lib.handle, "png_create_read_struct"); + if ( lib.png_create_read_struct == NULL ) { + SDL_UnloadObject(lib.handle); + return -1; + } + lib.png_destroy_read_struct = + (void (*) (png_structpp, png_infopp, png_infopp)) + SDL_LoadFunction(lib.handle, "png_destroy_read_struct"); + if ( lib.png_destroy_read_struct == NULL ) { + SDL_UnloadObject(lib.handle); + return -1; + } + lib.png_get_IHDR = + (png_uint_32 (*) (png_structp, png_infop, png_uint_32 *, png_uint_32 *, int *, int *, int *, int *, int *)) + SDL_LoadFunction(lib.handle, "png_get_IHDR"); + if ( lib.png_get_IHDR == NULL ) { + SDL_UnloadObject(lib.handle); + return -1; + } + lib.png_get_channels = + (png_byte (*) (png_structp, png_infop)) + SDL_LoadFunction(lib.handle, "png_get_channels"); + if ( lib.png_get_channels == NULL ) { + SDL_UnloadObject(lib.handle); + return -1; + } + lib.png_get_io_ptr = + (png_voidp (*) (png_structp)) + SDL_LoadFunction(lib.handle, "png_get_io_ptr"); + if ( lib.png_get_io_ptr == NULL ) { + SDL_UnloadObject(lib.handle); + return -1; + } + lib.png_get_PLTE = + (png_uint_32 (*) (png_structp, png_infop, png_colorp *, int *)) + SDL_LoadFunction(lib.handle, "png_get_PLTE"); + if ( lib.png_get_PLTE == NULL ) { + SDL_UnloadObject(lib.handle); + return -1; + } + lib.png_get_tRNS = + (png_uint_32 (*) (png_structp, png_infop, png_bytep *, int *, png_color_16p *)) + SDL_LoadFunction(lib.handle, "png_get_tRNS"); + if ( lib.png_get_tRNS == NULL ) { + SDL_UnloadObject(lib.handle); + return -1; + } + lib.png_get_valid = + (png_uint_32 (*) (png_structp, png_infop, png_uint_32)) + SDL_LoadFunction(lib.handle, "png_get_valid"); + if ( lib.png_get_valid == NULL ) { + SDL_UnloadObject(lib.handle); + return -1; + } + lib.png_read_image = + (void (*) (png_structp, png_bytepp)) + SDL_LoadFunction(lib.handle, "png_read_image"); + if ( lib.png_read_image == NULL ) { + SDL_UnloadObject(lib.handle); + return -1; + } + lib.png_read_info = + (void (*) (png_structp, png_infop)) + SDL_LoadFunction(lib.handle, "png_read_info"); + if ( lib.png_read_info == NULL ) { + SDL_UnloadObject(lib.handle); + return -1; + } + lib.png_read_update_info = + (void (*) (png_structp, png_infop)) + SDL_LoadFunction(lib.handle, "png_read_update_info"); + if ( lib.png_read_update_info == NULL ) { + SDL_UnloadObject(lib.handle); + return -1; + } + lib.png_set_expand = + (void (*) (png_structp)) + SDL_LoadFunction(lib.handle, "png_set_expand"); + if ( lib.png_set_expand == NULL ) { + SDL_UnloadObject(lib.handle); + return -1; + } + lib.png_set_gray_to_rgb = + (void (*) (png_structp)) + SDL_LoadFunction(lib.handle, "png_set_gray_to_rgb"); + if ( lib.png_set_gray_to_rgb == NULL ) { + SDL_UnloadObject(lib.handle); + return -1; + } + lib.png_set_packing = + (void (*) (png_structp)) + SDL_LoadFunction(lib.handle, "png_set_packing"); + if ( lib.png_set_packing == NULL ) { + SDL_UnloadObject(lib.handle); + return -1; + } + lib.png_set_read_fn = + (void (*) (png_structp, png_voidp, png_rw_ptr)) + SDL_LoadFunction(lib.handle, "png_set_read_fn"); + if ( lib.png_set_read_fn == NULL ) { + SDL_UnloadObject(lib.handle); + return -1; + } + lib.png_set_strip_16 = + (void (*) (png_structp)) + SDL_LoadFunction(lib.handle, "png_set_strip_16"); + if ( lib.png_set_strip_16 == NULL ) { + SDL_UnloadObject(lib.handle); + return -1; + } + lib.png_sig_cmp = + (int (*) (png_bytep, png_size_t, png_size_t)) + SDL_LoadFunction(lib.handle, "png_sig_cmp"); + if ( lib.png_sig_cmp == NULL ) { + SDL_UnloadObject(lib.handle); + return -1; + } +#ifndef LIBPNG_VERSION_12 + lib.png_set_longjmp_fn = + (jmp_buf * (*) (png_structp, png_longjmp_ptr, size_t)) + SDL_LoadFunction(lib.handle, "png_set_longjmp_fn"); + if ( lib.png_set_longjmp_fn == NULL ) { + SDL_UnloadObject(lib.handle); + return -1; + } +#endif + } + ++lib.loaded; + + return 0; +} +void IMG_QuitPNG() +{ + if ( lib.loaded == 0 ) { + return; + } + if ( lib.loaded == 1 ) { + SDL_UnloadObject(lib.handle); + } + --lib.loaded; +} +#else +int IMG_InitPNG() +{ + if ( lib.loaded == 0 ) { + lib.png_create_info_struct = png_create_info_struct; + lib.png_create_read_struct = png_create_read_struct; + lib.png_destroy_read_struct = png_destroy_read_struct; + lib.png_get_IHDR = png_get_IHDR; + lib.png_get_channels = png_get_channels; + lib.png_get_io_ptr = png_get_io_ptr; + lib.png_get_PLTE = png_get_PLTE; + lib.png_get_tRNS = png_get_tRNS; + lib.png_get_valid = png_get_valid; + lib.png_read_image = png_read_image; + lib.png_read_info = png_read_info; + lib.png_read_update_info = png_read_update_info; + lib.png_set_expand = png_set_expand; + lib.png_set_gray_to_rgb = png_set_gray_to_rgb; + lib.png_set_packing = png_set_packing; + lib.png_set_read_fn = png_set_read_fn; + lib.png_set_strip_16 = png_set_strip_16; + lib.png_sig_cmp = png_sig_cmp; +#ifndef LIBPNG_VERSION_12 + lib.png_set_longjmp_fn = png_set_longjmp_fn; +#endif + } + ++lib.loaded; + + return 0; +} +void IMG_QuitPNG() +{ + if ( lib.loaded == 0 ) { + return; + } + if ( lib.loaded == 1 ) { + } + --lib.loaded; +} +#endif /* LOAD_PNG_DYNAMIC */ + +/* See if an image is contained in a data source */ +int IMG_isPNG(SDL_RWops *src) +{ + int start; + int is_PNG; + Uint8 magic[4]; + + if ( !src ) + return 0; + start = SDL_RWtell(src); + is_PNG = 0; + if ( SDL_RWread(src, magic, 1, sizeof(magic)) == sizeof(magic) ) { + if ( magic[0] == 0x89 && + magic[1] == 'P' && + magic[2] == 'N' && + magic[3] == 'G' ) { + is_PNG = 1; + } + } + SDL_RWseek(src, start, RW_SEEK_SET); + return(is_PNG); +} + +/* Load a PNG type image from an SDL datasource */ +static void png_read_data(png_structp ctx, png_bytep area, png_size_t size) +{ + SDL_RWops *src; + + src = (SDL_RWops *)lib.png_get_io_ptr(ctx); + SDL_RWread(src, area, size, 1); +} +SDL_Surface *IMG_LoadPNG_RW(SDL_RWops *src) +{ + int start; + const char *error; + SDL_Surface *volatile surface; + png_structp png_ptr; + png_infop info_ptr; + png_uint_32 width, height; + int bit_depth, color_type, interlace_type, num_channels; + Uint32 Rmask; + Uint32 Gmask; + Uint32 Bmask; + Uint32 Amask; + SDL_Palette *palette; + png_bytep *volatile row_pointers; + int row, i; + volatile int ckey = -1; + png_color_16 *transv; + + if ( !src ) { + /* The error message has been set in SDL_RWFromFile */ + return NULL; + } + start = SDL_RWtell(src); + + if ( !IMG_Init(IMG_INIT_PNG) ) { + return NULL; + } + + /* Initialize the data we will clean up when we're done */ + error = NULL; + png_ptr = NULL; info_ptr = NULL; row_pointers = NULL; surface = NULL; + + /* Create the PNG loading context structure */ + png_ptr = lib.png_create_read_struct(PNG_LIBPNG_VER_STRING, + NULL,NULL,NULL); + if (png_ptr == NULL){ + error = "Couldn't allocate memory for PNG file or incompatible PNG dll"; + goto done; + } + + /* Allocate/initialize the memory for image information. REQUIRED. */ + info_ptr = lib.png_create_info_struct(png_ptr); + if (info_ptr == NULL) { + error = "Couldn't create image information for PNG file"; + goto done; + } + + /* Set error handling if you are using setjmp/longjmp method (this is + * the normal method of doing things with libpng). REQUIRED unless you + * set up your own error handlers in png_create_read_struct() earlier. + */ +#ifndef LIBPNG_VERSION_12 + if ( setjmp(*lib.png_set_longjmp_fn(png_ptr, longjmp, sizeof (jmp_buf))) ) +#else + if ( setjmp(png_ptr->jmpbuf) ) +#endif + { + error = "Error reading the PNG file."; + goto done; + } + + /* Set up the input control */ + lib.png_set_read_fn(png_ptr, src, png_read_data); + + /* Read PNG header info */ + lib.png_read_info(png_ptr, info_ptr); + lib.png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, + &color_type, &interlace_type, NULL, NULL); + + /* tell libpng to strip 16 bit/color files down to 8 bits/color */ + lib.png_set_strip_16(png_ptr) ; + + /* Extract multiple pixels with bit depths of 1, 2, and 4 from a single + * byte into separate bytes (useful for paletted and grayscale images). + */ + lib.png_set_packing(png_ptr); + + /* scale greyscale values to the range 0..255 */ + if(color_type == PNG_COLOR_TYPE_GRAY) + lib.png_set_expand(png_ptr); + + /* For images with a single "transparent colour", set colour key; + if more than one index has transparency, or if partially transparent + entries exist, use full alpha channel */ + if (lib.png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { + int num_trans; + Uint8 *trans; + lib.png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, + &transv); + if(color_type == PNG_COLOR_TYPE_PALETTE) { + /* Check if all tRNS entries are opaque except one */ + int i, t = -1; + for(i = 0; i < num_trans; i++) + if(trans[i] == 0) { + if(t >= 0) + break; + t = i; + } else if(trans[i] != 255) + break; + if(i == num_trans) { + /* exactly one transparent index */ + ckey = t; + } else { + /* more than one transparent index, or translucency */ + lib.png_set_expand(png_ptr); + } + } else + ckey = 0; /* actual value will be set later */ + } + + if ( color_type == PNG_COLOR_TYPE_GRAY_ALPHA ) + lib.png_set_gray_to_rgb(png_ptr); + + lib.png_read_update_info(png_ptr, info_ptr); + + lib.png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, + &color_type, &interlace_type, NULL, NULL); + + /* Allocate the SDL surface to hold the image */ + Rmask = Gmask = Bmask = Amask = 0 ; + num_channels = lib.png_get_channels(png_ptr, info_ptr); + if ( color_type != PNG_COLOR_TYPE_PALETTE ) { + if ( SDL_BYTEORDER == SDL_LIL_ENDIAN ) { + Rmask = 0x000000FF; + Gmask = 0x0000FF00; + Bmask = 0x00FF0000; + Amask = (num_channels == 4) ? 0xFF000000 : 0; + } else { + int s = (num_channels == 4) ? 0 : 8; + Rmask = 0xFF000000 >> s; + Gmask = 0x00FF0000 >> s; + Bmask = 0x0000FF00 >> s; + Amask = 0x000000FF >> s; + } + } + surface = SDL_AllocSurface(SDL_SWSURFACE, width, height, + bit_depth*num_channels, Rmask,Gmask,Bmask,Amask); + if ( surface == NULL ) { + error = "Out of memory"; + goto done; + } + + if(ckey != -1) { + if(color_type != PNG_COLOR_TYPE_PALETTE) + /* FIXME: Should these be truncated or shifted down? */ + ckey = SDL_MapRGB(surface->format, + (Uint8)transv->red, + (Uint8)transv->green, + (Uint8)transv->blue); + SDL_SetColorKey(surface, SDL_SRCCOLORKEY, ckey); + } + + /* Create the array of pointers to image data */ + row_pointers = (png_bytep*) malloc(sizeof(png_bytep)*height); + if ( (row_pointers == NULL) ) { + error = "Out of memory"; + goto done; + } + for (row = 0; row < (int)height; row++) { + row_pointers[row] = (png_bytep) + (Uint8 *)surface->pixels + row*surface->pitch; + } + + /* Read the entire image in one go */ + lib.png_read_image(png_ptr, row_pointers); + + /* and we're done! (png_read_end() can be omitted if no processing of + * post-IDAT text/time/etc. is desired) + * In some cases it can't read PNG's created by some popular programs (ACDSEE), + * we do not want to process comments, so we omit png_read_end + + lib.png_read_end(png_ptr, info_ptr); + */ + + /* Load the palette, if any */ + palette = surface->format->palette; + if ( palette ) { + int png_num_palette; + png_colorp png_palette; + lib.png_get_PLTE(png_ptr, info_ptr, &png_palette, &png_num_palette); + if(color_type == PNG_COLOR_TYPE_GRAY) { + palette->ncolors = 256; + for(i = 0; i < 256; i++) { + palette->colors[i].r = i; + palette->colors[i].g = i; + palette->colors[i].b = i; + } + } else if (png_num_palette > 0 ) { + palette->ncolors = png_num_palette; + for( i=0; icolors[i].b = png_palette[i].blue; + palette->colors[i].g = png_palette[i].green; + palette->colors[i].r = png_palette[i].red; + } + } + } + +done: /* Clean up and return */ + if ( png_ptr ) { + lib.png_destroy_read_struct(&png_ptr, + info_ptr ? &info_ptr : (png_infopp)0, + (png_infopp)0); + } + if ( row_pointers ) { + free(row_pointers); + } + if ( error ) { + SDL_RWseek(src, start, RW_SEEK_SET); + if ( surface ) { + SDL_FreeSurface(surface); + surface = NULL; + } + IMG_SetError(error); + } + return(surface); +} + +#else + +int IMG_InitPNG() +{ + IMG_SetError("PNG images are not supported"); + return(-1); +} + +void IMG_QuitPNG() +{ +} + +/* See if an image is contained in a data source */ +int IMG_isPNG(SDL_RWops *src) +{ + return(0); +} + +/* Load a PNG type image from an SDL datasource */ +SDL_Surface *IMG_LoadPNG_RW(SDL_RWops *src) +{ + return(NULL); +} + +#endif /* LOAD_PNG */ + +#endif /* !defined(__APPLE__) || defined(SDL_IMAGE_USE_COMMON_BACKEND) */ diff --git a/engines/vileVN/external/SDL/image/IMG_pnm.c b/engines/vileVN/external/SDL/image/IMG_pnm.c new file mode 100644 index 0000000000..0787f52aff --- /dev/null +++ b/engines/vileVN/external/SDL/image/IMG_pnm.c @@ -0,0 +1,258 @@ +/* + SDL_image: An example image loading library for use with SDL + Copyright (C) 1997-2012 Sam Lantinga + + 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. +*/ + +/* + * PNM (portable anymap) image loader: + * + * Supports: PBM, PGM and PPM, ASCII and binary formats + * (PBM and PGM are loaded as 8bpp surfaces) + * Does not support: maximum component value > 255 + */ + +#include +#include +#include +#include + +#include "SDL_image.h" + +#ifdef LOAD_PNM + +/* See if an image is contained in a data source */ +int IMG_isPNM(SDL_RWops *src) +{ + int start; + int is_PNM; + char magic[2]; + + if ( !src ) + return 0; + start = SDL_RWtell(src); + is_PNM = 0; + if ( SDL_RWread(src, magic, sizeof(magic), 1) ) { + /* + * PNM magic signatures: + * P1 PBM, ascii format + * P2 PGM, ascii format + * P3 PPM, ascii format + * P4 PBM, binary format + * P5 PGM, binary format + * P6 PPM, binary format + * P7 PAM, a general wrapper for PNM data + */ + if ( magic[0] == 'P' && magic[1] >= '1' && magic[1] <= '6' ) { + is_PNM = 1; + } + } + SDL_RWseek(src, start, RW_SEEK_SET); + return(is_PNM); +} + +/* read a non-negative integer from the source. return -1 upon error */ +static int ReadNumber(SDL_RWops *src) +{ + int number; + unsigned char ch; + + /* Initialize return value */ + number = 0; + + /* Skip leading whitespace */ + do { + if ( ! SDL_RWread(src, &ch, 1, 1) ) { + return(0); + } + /* Eat comments as whitespace */ + if ( ch == '#' ) { /* Comment is '#' to end of line */ + do { + if ( ! SDL_RWread(src, &ch, 1, 1) ) { + return -1; + } + } while ( (ch != '\r') && (ch != '\n') ); + } + } while ( isspace(ch) ); + + /* Add up the number */ + do { + number *= 10; + number += ch-'0'; + + if ( !SDL_RWread(src, &ch, 1, 1) ) { + return -1; + } + } while ( isdigit(ch) ); + + return(number); +} + +SDL_Surface *IMG_LoadPNM_RW(SDL_RWops *src) +{ + int start; + SDL_Surface *surface = NULL; + int width, height; + int maxval, y, bpl; + Uint8 *row; + Uint8 *buf = NULL; + char *error = NULL; + Uint8 magic[2]; + int ascii; + enum { PBM, PGM, PPM, PAM } kind; + +#define ERROR(s) do { error = (s); goto done; } while(0) + + if ( !src ) { + /* The error message has been set in SDL_RWFromFile */ + return NULL; + } + start = SDL_RWtell(src); + + SDL_RWread(src, magic, 2, 1); + kind = magic[1] - '1'; + ascii = 1; + if(kind >= 3) { + ascii = 0; + kind -= 3; + } + + width = ReadNumber(src); + height = ReadNumber(src); + if(width <= 0 || height <= 0) + ERROR("Unable to read image width and height"); + + if(kind != PBM) { + maxval = ReadNumber(src); + if(maxval <= 0 || maxval > 255) + ERROR("unsupported PNM format"); + } else + maxval = 255; /* never scale PBMs */ + + /* binary PNM allows just a single character of whitespace after + the last parameter, and we've already consumed it */ + + if(kind == PPM) { + /* 24-bit surface in R,G,B byte order */ + surface = SDL_AllocSurface(SDL_SWSURFACE, width, height, 24, +#if SDL_BYTEORDER == SDL_LIL_ENDIAN + 0x000000ff, 0x0000ff00, 0x00ff0000, +#else + 0x00ff0000, 0x0000ff00, 0x000000ff, +#endif + 0); + } else { + /* load PBM/PGM as 8-bit indexed images */ + surface = SDL_AllocSurface(SDL_SWSURFACE, width, height, 8, + 0, 0, 0, 0); + } + if ( surface == NULL ) + ERROR("Out of memory"); + bpl = width * surface->format->BytesPerPixel; + if(kind == PGM) { + SDL_Color *c = surface->format->palette->colors; + int i; + for(i = 0; i < 256; i++) + c[i].r = c[i].g = c[i].b = i; + surface->format->palette->ncolors = 256; + } else if(kind == PBM) { + /* for some reason PBM has 1=black, 0=white */ + SDL_Color *c = surface->format->palette->colors; + c[0].r = c[0].g = c[0].b = 255; + c[1].r = c[1].g = c[1].b = 0; + surface->format->palette->ncolors = 2; + bpl = (width + 7) >> 3; + buf = malloc(bpl); + if(buf == NULL) + ERROR("Out of memory"); + } + + /* Read the image into the surface */ + row = surface->pixels; + for(y = 0; y < height; y++) { + if(ascii) { + int i; + if(kind == PBM) { + for(i = 0; i < width; i++) { + Uint8 ch; + do { + if(!SDL_RWread(src, &ch, + 1, 1)) + ERROR("file truncated"); + ch -= '0'; + } while(ch > 1); + row[i] = ch; + } + } else { + for(i = 0; i < bpl; i++) { + int c; + c = ReadNumber(src); + if(c < 0) + ERROR("file truncated"); + row[i] = c; + } + } + } else { + Uint8 *dst = (kind == PBM) ? buf : row; + if(!SDL_RWread(src, dst, bpl, 1)) + ERROR("file truncated"); + if(kind == PBM) { + /* expand bitmap to 8bpp */ + int i; + for(i = 0; i < width; i++) { + int bit = 7 - (i & 7); + row[i] = (buf[i >> 3] >> bit) & 1; + } + } + } + if(maxval < 255) { + /* scale up to full dynamic range (slow) */ + int i; + for(i = 0; i < bpl; i++) + row[i] = row[i] * 255 / maxval; + } + row += surface->pitch; + } +done: + free(buf); + if(error) { + SDL_RWseek(src, start, RW_SEEK_SET); + if ( surface ) { + SDL_FreeSurface(surface); + surface = NULL; + } + IMG_SetError(error); + } + return(surface); +} + +#else + +/* See if an image is contained in a data source */ +int IMG_isPNM(SDL_RWops *src) +{ + return(0); +} + +/* Load a PNM type image from an SDL datasource */ +SDL_Surface *IMG_LoadPNM_RW(SDL_RWops *src) +{ + return(NULL); +} + +#endif /* LOAD_PNM */ diff --git a/engines/vileVN/external/SDL/image/IMG_tga.c b/engines/vileVN/external/SDL/image/IMG_tga.c new file mode 100644 index 0000000000..0e65c5d320 --- /dev/null +++ b/engines/vileVN/external/SDL/image/IMG_tga.c @@ -0,0 +1,336 @@ +/* + SDL_image: An example image loading library for use with SDL + Copyright (C) 1997-2012 Sam Lantinga + + 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. +*/ + +#if !defined(__APPLE__) || defined(SDL_IMAGE_USE_COMMON_BACKEND) + +/* This is a Targa image file loading framework */ + +#include +#include +#include + +#include "SDL_endian.h" + +#include "SDL_image.h" + +#ifdef LOAD_TGA + +/* + * A TGA loader for the SDL library + * Supports: Reading 8, 15, 16, 24 and 32bpp images, with alpha or colourkey, + * uncompressed or RLE encoded. + * + * 2000-06-10 Mattias Engdegård : initial version + * 2000-06-26 Mattias Engdegård : read greyscale TGAs + * 2000-08-09 Mattias Engdegård : alpha inversion removed + */ + +struct TGAheader { + Uint8 infolen; /* length of info field */ + Uint8 has_cmap; /* 1 if image has colormap, 0 otherwise */ + Uint8 type; + + Uint8 cmap_start[2]; /* index of first colormap entry */ + Uint8 cmap_len[2]; /* number of entries in colormap */ + Uint8 cmap_bits; /* bits per colormap entry */ + + Uint8 yorigin[2]; /* image origin (ignored here) */ + Uint8 xorigin[2]; + Uint8 width[2]; /* image size */ + Uint8 height[2]; + Uint8 pixel_bits; /* bits/pixel */ + Uint8 flags; +}; + +enum tga_type { + TGA_TYPE_INDEXED = 1, + TGA_TYPE_RGB = 2, + TGA_TYPE_BW = 3, + TGA_TYPE_RLE_INDEXED = 9, + TGA_TYPE_RLE_RGB = 10, + TGA_TYPE_RLE_BW = 11 +}; + +#define TGA_INTERLEAVE_MASK 0xc0 +#define TGA_INTERLEAVE_NONE 0x00 +#define TGA_INTERLEAVE_2WAY 0x40 +#define TGA_INTERLEAVE_4WAY 0x80 + +#define TGA_ORIGIN_MASK 0x30 +#define TGA_ORIGIN_LEFT 0x00 +#define TGA_ORIGIN_RIGHT 0x10 +#define TGA_ORIGIN_LOWER 0x00 +#define TGA_ORIGIN_UPPER 0x20 + +/* read/write unaligned little-endian 16-bit ints */ +#define LE16(p) ((p)[0] + ((p)[1] << 8)) +#define SETLE16(p, v) ((p)[0] = (v), (p)[1] = (v) >> 8) + +/* Load a TGA type image from an SDL datasource */ +SDL_Surface *IMG_LoadTGA_RW(SDL_RWops *src) +{ + int start; + const char *error = NULL; + struct TGAheader hdr; + int rle = 0; + int alpha = 0; + int indexed = 0; + int grey = 0; + int ckey = -1; + int ncols, w, h; + SDL_Surface *img = NULL; + Uint32 rmask, gmask, bmask, amask; + Uint8 *dst; + int i; + int bpp; + int lstep; + Uint32 pixel; + int count, rep; + + if ( !src ) { + /* The error message has been set in SDL_RWFromFile */ + return NULL; + } + start = SDL_RWtell(src); + + if(!SDL_RWread(src, &hdr, sizeof(hdr), 1)) { + error = "Error reading TGA data"; + goto error; + } + ncols = LE16(hdr.cmap_len); + switch(hdr.type) { + case TGA_TYPE_RLE_INDEXED: + rle = 1; + /* fallthrough */ + case TGA_TYPE_INDEXED: + if(!hdr.has_cmap || hdr.pixel_bits != 8 || ncols > 256) + goto unsupported; + indexed = 1; + break; + + case TGA_TYPE_RLE_RGB: + rle = 1; + /* fallthrough */ + case TGA_TYPE_RGB: + indexed = 0; + break; + + case TGA_TYPE_RLE_BW: + rle = 1; + /* fallthrough */ + case TGA_TYPE_BW: + if(hdr.pixel_bits != 8) + goto unsupported; + /* Treat greyscale as 8bpp indexed images */ + indexed = grey = 1; + break; + + default: + goto unsupported; + } + + bpp = (hdr.pixel_bits + 7) >> 3; + rmask = gmask = bmask = amask = 0; + switch(hdr.pixel_bits) { + case 8: + if(!indexed) { + goto unsupported; + } + break; + + case 15: + case 16: + /* 15 and 16bpp both seem to use 5 bits/plane. The extra alpha bit + is ignored for now. */ + rmask = 0x7c00; + gmask = 0x03e0; + bmask = 0x001f; + break; + + case 32: + alpha = 1; + /* fallthrough */ + case 24: + if(SDL_BYTEORDER == SDL_BIG_ENDIAN) { + int s = alpha ? 0 : 8; + amask = 0x000000ff >> s; + rmask = 0x0000ff00 >> s; + gmask = 0x00ff0000 >> s; + bmask = 0xff000000 >> s; + } else { + amask = alpha ? 0xff000000 : 0; + rmask = 0x00ff0000; + gmask = 0x0000ff00; + bmask = 0x000000ff; + } + break; + + default: + goto unsupported; + } + + if((hdr.flags & TGA_INTERLEAVE_MASK) != TGA_INTERLEAVE_NONE + || hdr.flags & TGA_ORIGIN_RIGHT) { + goto unsupported; + } + + SDL_RWseek(src, hdr.infolen, RW_SEEK_CUR); /* skip info field */ + + w = LE16(hdr.width); + h = LE16(hdr.height); + img = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, + bpp * 8, + rmask, gmask, bmask, amask); + if(img == NULL) { + error = "Out of memory"; + goto error; + } + + if(hdr.has_cmap) { + int palsiz = ncols * ((hdr.cmap_bits + 7) >> 3); + if(indexed && !grey) { + Uint8 *pal = malloc(palsiz), *p = pal; + SDL_Color *colors = img->format->palette->colors; + img->format->palette->ncolors = ncols; + SDL_RWread(src, pal, palsiz, 1); + for(i = 0; i < ncols; i++) { + switch(hdr.cmap_bits) { + case 15: + case 16: + { + Uint16 c = p[0] + (p[1] << 8); + p += 2; + colors[i].r = (c >> 7) & 0xf8; + colors[i].g = (c >> 2) & 0xf8; + colors[i].b = c << 3; + } + break; + case 24: + case 32: + colors[i].b = *p++; + colors[i].g = *p++; + colors[i].r = *p++; + if(hdr.cmap_bits == 32 && *p++ < 128) + ckey = i; + break; + } + } + free(pal); + if(ckey >= 0) + SDL_SetColorKey(img, SDL_SRCCOLORKEY, ckey); + } else { + /* skip unneeded colormap */ + SDL_RWseek(src, palsiz, RW_SEEK_CUR); + } + } + + if(grey) { + SDL_Color *colors = img->format->palette->colors; + for(i = 0; i < 256; i++) + colors[i].r = colors[i].g = colors[i].b = i; + img->format->palette->ncolors = 256; + } + + if(hdr.flags & TGA_ORIGIN_UPPER) { + lstep = img->pitch; + dst = img->pixels; + } else { + lstep = -img->pitch; + dst = (Uint8 *)img->pixels + (h - 1) * img->pitch; + } + + /* The RLE decoding code is slightly convoluted since we can't rely on + spans not to wrap across scan lines */ + count = rep = 0; + for(i = 0; i < h; i++) { + if(rle) { + int x = 0; + for(;;) { + Uint8 c; + + if(count) { + int n = count; + if(n > w - x) + n = w - x; + SDL_RWread(src, dst + x * bpp, n * bpp, 1); + count -= n; + x += n; + if(x == w) + break; + } else if(rep) { + int n = rep; + if(n > w - x) + n = w - x; + rep -= n; + while(n--) { + memcpy(dst + x * bpp, &pixel, bpp); + x++; + } + if(x == w) + break; + } + + SDL_RWread(src, &c, 1, 1); + if(c & 0x80) { + SDL_RWread(src, &pixel, bpp, 1); + rep = (c & 0x7f) + 1; + } else { + count = c + 1; + } + } + + } else { + SDL_RWread(src, dst, w * bpp, 1); + } + if(SDL_BYTEORDER == SDL_BIG_ENDIAN && bpp == 2) { + /* swap byte order */ + int x; + Uint16 *p = (Uint16 *)dst; + for(x = 0; x < w; x++) + p[x] = SDL_Swap16(p[x]); + } + dst += lstep; + } + return img; + +unsupported: + error = "Unsupported TGA format"; + +error: + SDL_RWseek(src, start, RW_SEEK_SET); + if ( img ) { + SDL_FreeSurface(img); + } + IMG_SetError(error); + return NULL; +} + +#else + +/* dummy TGA load routine */ +SDL_Surface *IMG_LoadTGA_RW(SDL_RWops *src) +{ + return(NULL); +} + +#endif /* LOAD_TGA */ + +#endif /* !defined(__APPLE__) || defined(SDL_IMAGE_USE_COMMON_BACKEND) */ diff --git a/engines/vileVN/external/SDL/image/IMG_tif.c b/engines/vileVN/external/SDL/image/IMG_tif.c new file mode 100644 index 0000000000..25084ad7ac --- /dev/null +++ b/engines/vileVN/external/SDL/image/IMG_tif.c @@ -0,0 +1,298 @@ +/* + SDL_image: An example image loading library for use with SDL + Copyright (C) 1997-2012 Sam Lantinga + + 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. +*/ + +#if !defined(__APPLE__) || defined(SDL_IMAGE_USE_COMMON_BACKEND) + +/* This is a TIFF image file loading framework */ + +#include + +#include "SDL_image.h" + +#ifdef LOAD_TIF + +#include + +static struct { + int loaded; + void *handle; + TIFF* (*TIFFClientOpen)(const char*, const char*, thandle_t, TIFFReadWriteProc, TIFFReadWriteProc, TIFFSeekProc, TIFFCloseProc, TIFFSizeProc, TIFFMapFileProc, TIFFUnmapFileProc); + void (*TIFFClose)(TIFF*); + int (*TIFFGetField)(TIFF*, ttag_t, ...); + int (*TIFFReadRGBAImage)(TIFF*, uint32, uint32, uint32*, int); + TIFFErrorHandler (*TIFFSetErrorHandler)(TIFFErrorHandler); +} lib; + +#ifdef LOAD_TIF_DYNAMIC +int IMG_InitTIF() +{ + if ( lib.loaded == 0 ) { + lib.handle = SDL_LoadObject(LOAD_TIF_DYNAMIC); + if ( lib.handle == NULL ) { + return -1; + } + lib.TIFFClientOpen = + (TIFF* (*)(const char*, const char*, thandle_t, TIFFReadWriteProc, TIFFReadWriteProc, TIFFSeekProc, TIFFCloseProc, TIFFSizeProc, TIFFMapFileProc, TIFFUnmapFileProc)) + SDL_LoadFunction(lib.handle, "TIFFClientOpen"); + if ( lib.TIFFClientOpen == NULL ) { + SDL_UnloadObject(lib.handle); + return -1; + } + lib.TIFFClose = + (void (*)(TIFF*)) + SDL_LoadFunction(lib.handle, "TIFFClose"); + if ( lib.TIFFClose == NULL ) { + SDL_UnloadObject(lib.handle); + return -1; + } + lib.TIFFGetField = + (int (*)(TIFF*, ttag_t, ...)) + SDL_LoadFunction(lib.handle, "TIFFGetField"); + if ( lib.TIFFGetField == NULL ) { + SDL_UnloadObject(lib.handle); + return -1; + } + lib.TIFFReadRGBAImage = + (int (*)(TIFF*, uint32, uint32, uint32*, int)) + SDL_LoadFunction(lib.handle, "TIFFReadRGBAImage"); + if ( lib.TIFFReadRGBAImage == NULL ) { + SDL_UnloadObject(lib.handle); + return -1; + } + lib.TIFFSetErrorHandler = + (TIFFErrorHandler (*)(TIFFErrorHandler)) + SDL_LoadFunction(lib.handle, "TIFFSetErrorHandler"); + if ( lib.TIFFSetErrorHandler == NULL ) { + SDL_UnloadObject(lib.handle); + return -1; + } + } + ++lib.loaded; + + return 0; +} +void IMG_QuitTIF() +{ + if ( lib.loaded == 0 ) { + return; + } + if ( lib.loaded == 1 ) { + SDL_UnloadObject(lib.handle); + } + --lib.loaded; +} +#else +int IMG_InitTIF() +{ + if ( lib.loaded == 0 ) { + lib.TIFFClientOpen = TIFFClientOpen; + lib.TIFFClose = TIFFClose; + lib.TIFFGetField = TIFFGetField; + lib.TIFFReadRGBAImage = TIFFReadRGBAImage; + lib.TIFFSetErrorHandler = TIFFSetErrorHandler; + } + ++lib.loaded; + + return 0; +} +void IMG_QuitTIF() +{ + if ( lib.loaded == 0 ) { + return; + } + if ( lib.loaded == 1 ) { + } + --lib.loaded; +} +#endif /* LOAD_TIF_DYNAMIC */ + +/* + * These are the thunking routine to use the SDL_RWops* routines from + * libtiff's internals. +*/ + +static tsize_t tiff_read(thandle_t fd, tdata_t buf, tsize_t size) +{ + return SDL_RWread((SDL_RWops*)fd, buf, 1, size); +} + +static toff_t tiff_seek(thandle_t fd, toff_t offset, int origin) +{ + return SDL_RWseek((SDL_RWops*)fd, offset, origin); +} + +static tsize_t tiff_write(thandle_t fd, tdata_t buf, tsize_t size) +{ + return SDL_RWwrite((SDL_RWops*)fd, buf, 1, size); +} + +static int tiff_close(thandle_t fd) +{ + /* + * We don't want libtiff closing our SDL_RWops*, but if it's not given + * a routine to try, and if the image isn't a TIFF, it'll segfault. + */ + return 0; +} + +static int tiff_map(thandle_t fd, tdata_t* pbase, toff_t* psize) +{ + return (0); +} + +static void tiff_unmap(thandle_t fd, tdata_t base, toff_t size) +{ + return; +} + +static toff_t tiff_size(thandle_t fd) +{ + Uint32 save_pos; + toff_t size; + + save_pos = SDL_RWtell((SDL_RWops*)fd); + SDL_RWseek((SDL_RWops*)fd, 0, RW_SEEK_END); + size = SDL_RWtell((SDL_RWops*)fd); + SDL_RWseek((SDL_RWops*)fd, save_pos, RW_SEEK_SET); + return size; +} + +int IMG_isTIF(SDL_RWops* src) +{ + int start; + int is_TIF; + Uint8 magic[4]; + + if ( !src ) + return 0; + start = SDL_RWtell(src); + is_TIF = 0; + if ( SDL_RWread(src, magic, 1, sizeof(magic)) == sizeof(magic) ) { + if ( (magic[0] == 'I' && + magic[1] == 'I' && + magic[2] == 0x2a && + magic[3] == 0x00) || + (magic[0] == 'M' && + magic[1] == 'M' && + magic[2] == 0x00 && + magic[3] == 0x2a) ) { + is_TIF = 1; + } + } + SDL_RWseek(src, start, RW_SEEK_SET); + return(is_TIF); +} + +SDL_Surface* IMG_LoadTIF_RW(SDL_RWops* src) +{ + int start; + TIFF* tiff; + SDL_Surface* surface = NULL; + Uint32 img_width, img_height; + Uint32 Rmask, Gmask, Bmask, Amask; + Uint32 x, y; + Uint32 half; + + if ( !src ) { + /* The error message has been set in SDL_RWFromFile */ + return NULL; + } + start = SDL_RWtell(src); + + if ( !IMG_Init(IMG_INIT_TIF) ) { + return NULL; + } + + /* turn off memory mapped access with the m flag */ + tiff = lib.TIFFClientOpen("SDL_image", "rm", (thandle_t)src, + tiff_read, tiff_write, tiff_seek, tiff_close, tiff_size, tiff_map, tiff_unmap); + if(!tiff) + goto error; + + /* Retrieve the dimensions of the image from the TIFF tags */ + lib.TIFFGetField(tiff, TIFFTAG_IMAGEWIDTH, &img_width); + lib.TIFFGetField(tiff, TIFFTAG_IMAGELENGTH, &img_height); + + Rmask = 0x000000FF; + Gmask = 0x0000FF00; + Bmask = 0x00FF0000; + Amask = 0xFF000000; + surface = SDL_AllocSurface(SDL_SWSURFACE, img_width, img_height, 32, + Rmask, Gmask, Bmask, Amask); + if(!surface) + goto error; + + if(!lib.TIFFReadRGBAImage(tiff, img_width, img_height, surface->pixels, 0)) + goto error; + + /* libtiff loads the image upside-down, flip it back */ + half = img_height / 2; + for(y = 0; y < half; y++) + { + Uint32 *top = (Uint32 *)surface->pixels + y * surface->pitch/4; + Uint32 *bot = (Uint32 *)surface->pixels + + (img_height - y - 1) * surface->pitch/4; + for(x = 0; x < img_width; x++) + { + Uint32 tmp = top[x]; + top[x] = bot[x]; + bot[x] = tmp; + } + } + lib.TIFFClose(tiff); + + return surface; + +error: + SDL_RWseek(src, start, RW_SEEK_SET); + if ( surface ) { + SDL_FreeSurface(surface); + } + return NULL; +} + +#else + +int IMG_InitTIF() +{ + IMG_SetError("TIFF images are not supported"); + return(-1); +} + +void IMG_QuitTIF() +{ +} + +/* See if an image is contained in a data source */ +int IMG_isTIF(SDL_RWops *src) +{ + return(0); +} + +/* Load a TIFF type image from an SDL datasource */ +SDL_Surface *IMG_LoadTIF_RW(SDL_RWops *src) +{ + return(NULL); +} + +#endif /* LOAD_TIF */ + +#endif /* !defined(__APPLE__) || defined(SDL_IMAGE_USE_COMMON_BACKEND) */ diff --git a/engines/vileVN/external/SDL/image/IMG_webp.c b/engines/vileVN/external/SDL/image/IMG_webp.c new file mode 100644 index 0000000000..94727ce195 --- /dev/null +++ b/engines/vileVN/external/SDL/image/IMG_webp.c @@ -0,0 +1,295 @@ +/* + SDL_image: An example image loading library for use with SDL + Copyright (C) 1997-2012 Sam Lantinga + + 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. +*/ + +/* This is a WEBP image file loading framework */ + +#include +#include + +#include "SDL_image.h" + +#ifdef LOAD_WEBP + +/*============================================================================= + File: SDL_webp.c + Purpose: A WEBP loader for the SDL library + Revision: + Created by: Michael Bonfils (Murlock) (26 November 2011) + murlock42@gmail.com + +=============================================================================*/ + +#include "SDL_endian.h" + +#ifdef macintosh +#define MACOS +#endif +#include + +static struct { + int loaded; + void *handle; + int/*VP8StatuCode*/ (*webp_get_features_internal) (const uint8_t *data, uint32_t data_size, WebPBitstreamFeatures* const features, int decoder_abi_version); + uint8_t* (*webp_decode_rgb_into) (const uint8_t* data, uint32_t data_size, uint8_t* output_buffer, int output_buffer_size, int output_stride); + uint8_t* (*webp_decode_rgba_into) (const uint8_t* data, uint32_t data_size, uint8_t* output_buffer, int output_buffer_size, int output_stride); +} lib; + +#ifdef LOAD_WEBP_DYNAMIC +int IMG_InitWEBP() +{ + if ( lib.loaded == 0 ) { + lib.handle = SDL_LoadObject(LOAD_WEBP_DYNAMIC); + if ( lib.handle == NULL ) { + return -1; + } + lib.webp_get_features_internal = + ( int (*) (const uint8_t *, uint32_t, WebPBitstreamFeatures* const, int) ) + SDL_LoadFunction(lib.handle, "WebPGetFeaturesInternal" ); + if ( lib.webp_get_features_internal == NULL ) { + SDL_UnloadObject(lib.handle); + return -1; + } + + lib.webp_decode_rgb_into = + ( uint8_t* (*) (const uint8_t*, uint32_t, uint8_t*, int, int ) ) + SDL_LoadFunction(lib.handle, "WebPDecodeRGBInto" ); + if ( lib.webp_decode_rgb_into == NULL ) { + SDL_UnloadObject(lib.handle); + return -1; + } + + lib.webp_decode_rgba_into = + ( uint8_t* (*) (const uint8_t*, uint32_t, uint8_t*, int, int ) ) + SDL_LoadFunction(lib.handle, "WebPDecodeRGBInto" ); + if ( lib.webp_decode_rgba_into == NULL ) { + SDL_UnloadObject(lib.handle); + return -1; + } + } + ++lib.loaded; + + return 0; +} +void IMG_QuitWEBP() +{ + if ( lib.loaded == 0 ) { + return; + } + if ( lib.loaded == 1 ) { + SDL_UnloadObject(lib.handle); + } + --lib.loaded; +} +#else +int IMG_InitWEBP() +{ + if ( lib.loaded == 0 ) { + lib.webp_get_features_internal = WebPGetFeaturesInternal; + lib.webp_decode_rgb_into = WebPDecodeRGBInto; + lib.webp_decode_rgba_into = WebPDecodeRGBAInto; + } + ++lib.loaded; + + return 0; +} +void IMG_QuitWEBP() +{ + if ( lib.loaded == 0 ) { + return; + } + if ( lib.loaded == 1 ) { + } + --lib.loaded; +} +#endif /* LOAD_WEBP_DYNAMIC */ + +static int webp_getinfo( SDL_RWops *src, int *datasize ) { + int start; + int is_WEBP; + int data; + Uint8 magic[20]; + + if ( !src ) + return 0; + start = SDL_RWtell(src); + is_WEBP = 0; + if ( SDL_RWread(src, magic, 1, sizeof(magic)) == sizeof(magic) ) { + if ( magic[ 0] == 'R' && + magic[ 1] == 'I' && + magic[ 2] == 'F' && + magic[ 3] == 'F' && + magic[ 8] == 'W' && + magic[ 9] == 'E' && + magic[10] == 'B' && + magic[11] == 'P' && + magic[12] == 'V' && + magic[13] == 'P' && + magic[14] == '8' && + magic[15] == ' ' ) { + is_WEBP = 1; + data = magic[16] | magic[17]<<8 | magic[18]<<16 | magic[19]<<24; + if ( datasize ) + *datasize = data; + } + } + SDL_RWseek(src, start, RW_SEEK_SET); + return(is_WEBP); +} + +/* See if an image is contained in a data source */ +int IMG_isWEBP(SDL_RWops *src) +{ + return webp_getinfo( src, NULL ); +} + +SDL_Surface *IMG_LoadWEBP_RW(SDL_RWops *src) +{ + int start; + const char *error = NULL; + SDL_Surface *volatile surface = NULL; + Uint32 Rmask; + Uint32 Gmask; + Uint32 Bmask; + Uint32 Amask; + WebPBitstreamFeatures features; + int raw_data_size; + uint8_t *raw_data; + int r; + uint8_t *ret; + + if ( !src ) { + /* The error message has been set in SDL_RWFromFile */ + return NULL; + } + + start = SDL_RWtell(src); + + if ( !IMG_Init(IMG_INIT_WEBP) ) { + goto error; + } + + + raw_data_size = -1; + if ( !webp_getinfo( src, &raw_data_size ) ) { + error = "Invalid WEBP"; + goto error; + } + + // skip header + SDL_RWseek(src, start+20, RW_SEEK_SET ); + + raw_data = (uint8_t*) malloc( raw_data_size ); + if ( raw_data == NULL ) { + error = "Failed to allocate enought buffer for WEBP"; + goto error; + } + + r = SDL_RWread(src, raw_data, 1, raw_data_size ); + if ( r != raw_data_size ) { + error = "Failed to read WEBP"; + goto error; + } + +#if 0 + // extract size of picture, not interesting since we don't know about alpha channel + int width = -1, height = -1; + if ( !WebPGetInfo( raw_data, raw_data_size, &width, &height ) ) { + printf("WebPGetInfo has failed\n" ); + return NULL; + } +#endif + + if ( lib.webp_get_features_internal( raw_data, raw_data_size, &features, WEBP_DECODER_ABI_VERSION ) != VP8_STATUS_OK ) { + error = "WebPGetFeatures has failed"; + return NULL; + } + + /* Check if it's ok !*/ + Rmask = 0x000000FF; + Gmask = 0x0000FF00; + Bmask = 0x00FF0000; + Amask = features.has_alpha?0xFF000001:0; + + surface = SDL_AllocSurface(SDL_SWSURFACE, features.width, features.height, + features.has_alpha?32:24, Rmask,Gmask,Bmask,Amask); + + if ( surface == NULL ) { + error = "Failed to allocate SDL_Surface"; + goto error; + } + + if ( features.has_alpha ) { + ret = lib.webp_decode_rgba_into( raw_data, raw_data_size, surface->pixels, surface->pitch * surface->h, surface->pitch ); + } else { + ret = lib.webp_decode_rgb_into( raw_data, raw_data_size, surface->pixels, surface->pitch * surface->h, surface->pitch ); + } + + if ( !ret ) { + error = "Failed to decode WEBP"; + goto error; + } + + return surface; + + +error: + + if ( surface ) { + SDL_FreeSurface( surface ); + } + + if ( raw_data ) { + free( raw_data ); + } + + if ( error ) { + IMG_SetError( error ); + } + + SDL_RWseek(src, start, RW_SEEK_SET); + return(NULL); +} + +#else + +int IMG_InitWEBP() +{ + IMG_SetError("WEBP images are not supported"); + return(-1); +} + +void IMG_QuitWEBP() +{ +} + +/* See if an image is contained in a data source */ +int IMG_isWEBP(SDL_RWops *src) +{ + return(0); +} + +/* Load a WEBP type image from an SDL datasource */ +SDL_Surface *IMG_LoadWEBP_RW(SDL_RWops *src) +{ + return(NULL); +} + +#endif /* LOAD_WEBP */ diff --git a/engines/vileVN/external/SDL/image/IMG_xcf.c b/engines/vileVN/external/SDL/image/IMG_xcf.c new file mode 100644 index 0000000000..1dced65ee5 --- /dev/null +++ b/engines/vileVN/external/SDL/image/IMG_xcf.c @@ -0,0 +1,824 @@ +/* + SDL_image: An example image loading library for use with SDL + Copyright (C) 1997-2012 Sam Lantinga + + 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. +*/ + +/* This is a XCF image file loading framework */ + +#include +#include +#include +#include + +#include "SDL_endian.h" +#include "SDL_image.h" + +#ifdef LOAD_XCF + +#if DEBUG +static char prop_names [][30] = { + "end", + "colormap", + "active_layer", + "active_channel", + "selection", + "floating_selection", + "opacity", + "mode", + "visible", + "linked", + "preserve_transparency", + "apply_mask", + "edit_mask", + "show_mask", + "show_masked", + "offsets", + "color", + "compression", + "guides", + "resolution", + "tattoo", + "parasites", + "unit", + "paths", + "user_unit" +}; +#endif + + +typedef enum +{ + PROP_END = 0, + PROP_COLORMAP = 1, + PROP_ACTIVE_LAYER = 2, + PROP_ACTIVE_CHANNEL = 3, + PROP_SELECTION = 4, + PROP_FLOATING_SELECTION = 5, + PROP_OPACITY = 6, + PROP_MODE = 7, + PROP_VISIBLE = 8, + PROP_LINKED = 9, + PROP_PRESERVE_TRANSPARENCY = 10, + PROP_APPLY_MASK = 11, + PROP_EDIT_MASK = 12, + PROP_SHOW_MASK = 13, + PROP_SHOW_MASKED = 14, + PROP_OFFSETS = 15, + PROP_COLOR = 16, + PROP_COMPRESSION = 17, + PROP_GUIDES = 18, + PROP_RESOLUTION = 19, + PROP_TATTOO = 20, + PROP_PARASITES = 21, + PROP_UNIT = 22, + PROP_PATHS = 23, + PROP_USER_UNIT = 24 +} xcf_prop_type; + +typedef enum { + COMPR_NONE = 0, + COMPR_RLE = 1, + COMPR_ZLIB = 2, + COMPR_FRACTAL = 3 +} xcf_compr_type; + +typedef enum { + IMAGE_RGB = 0, + IMAGE_GREYSCALE = 1, + IMAGE_INDEXED = 2 +} xcf_image_type; + +typedef struct { + Uint32 id; + Uint32 length; + union { + struct { + Uint32 num; + char * cmap; + } colormap; // 1 + struct { + Uint32 drawable_offset; + } floating_selection; // 5 + Sint32 opacity; + Sint32 mode; + int visible; + int linked; + int preserve_transparency; + int apply_mask; + int show_mask; + struct { + Sint32 x; + Sint32 y; + } offset; + unsigned char color [3]; + Uint8 compression; + struct { + Sint32 x; + Sint32 y; + } resolution; + struct { + char * name; + Uint32 flags; + Uint32 size; + char * data; + } parasite; + } data; +} xcf_prop; + +typedef struct { + char sign [14]; + Uint32 width; + Uint32 height; + Sint32 image_type; + xcf_prop * properties; + + Uint32 * layer_file_offsets; + Uint32 * channel_file_offsets; + + xcf_compr_type compr; + Uint32 cm_num; + unsigned char * cm_map; +} xcf_header; + +typedef struct { + Uint32 width; + Uint32 height; + Sint32 layer_type; + char * name; + xcf_prop * properties; + + Uint32 hierarchy_file_offset; + Uint32 layer_mask_offset; + + Uint32 offset_x; + Uint32 offset_y; + int visible; +} xcf_layer; + +typedef struct { + Uint32 width; + Uint32 height; + char * name; + xcf_prop * properties; + + Uint32 hierarchy_file_offset; + + Uint32 color; + Uint32 opacity; + int selection; + int visible; +} xcf_channel; + +typedef struct { + Uint32 width; + Uint32 height; + Uint32 bpp; + + Uint32 * level_file_offsets; +} xcf_hierarchy; + +typedef struct { + Uint32 width; + Uint32 height; + + Uint32 * tile_file_offsets; +} xcf_level; + +typedef unsigned char * xcf_tile; + +typedef unsigned char * (* load_tile_type) (SDL_RWops *, Uint32, int, int, int); + + +/* See if an image is contained in a data source */ +int IMG_isXCF(SDL_RWops *src) +{ + int start; + int is_XCF; + char magic[14]; + + if ( !src ) + return 0; + start = SDL_RWtell(src); + is_XCF = 0; + if ( SDL_RWread(src, magic, sizeof(magic), 1) ) { + if (strncmp(magic, "gimp xcf ", 9) == 0) { + is_XCF = 1; + } + } + SDL_RWseek(src, start, RW_SEEK_SET); + return(is_XCF); +} + +static char * read_string (SDL_RWops * src) { + Uint32 tmp; + char * data; + + tmp = SDL_ReadBE32 (src); + if (tmp > 0) { + data = (char *) malloc (sizeof (char) * tmp); + SDL_RWread (src, data, tmp, 1); + } + else { + data = NULL; + } + + return data; +} + + +static Uint32 Swap32 (Uint32 v) { + return + ((v & 0x000000FF) << 16) + | ((v & 0x0000FF00)) + | ((v & 0x00FF0000) >> 16) + | ((v & 0xFF000000)); +} + +static void xcf_read_property (SDL_RWops * src, xcf_prop * prop) { + prop->id = SDL_ReadBE32 (src); + prop->length = SDL_ReadBE32 (src); + +#if DEBUG + printf ("%.8X: %s: %d\n", SDL_RWtell (src), prop->id < 25 ? prop_names [prop->id] : "unknown", prop->length); +#endif + + switch (prop->id) { + case PROP_COLORMAP: + prop->data.colormap.num = SDL_ReadBE32 (src); + prop->data.colormap.cmap = (char *) malloc (sizeof (char) * prop->data.colormap.num * 3); + SDL_RWread (src, prop->data.colormap.cmap, prop->data.colormap.num*3, 1); + break; + + case PROP_OFFSETS: + prop->data.offset.x = SDL_ReadBE32 (src); + prop->data.offset.y = SDL_ReadBE32 (src); + break; + case PROP_OPACITY: + prop->data.opacity = SDL_ReadBE32 (src); + break; + case PROP_COMPRESSION: + case PROP_COLOR: + SDL_RWread (src, &prop->data, prop->length, 1); + break; + case PROP_VISIBLE: + prop->data.visible = SDL_ReadBE32 (src); + break; + default: + // SDL_RWread (src, &prop->data, prop->length, 1); + SDL_RWseek (src, prop->length, RW_SEEK_CUR); + } +} + +static void free_xcf_header (xcf_header * h) { + if (h->cm_num) + free (h->cm_map); + + free (h); +} + +static xcf_header * read_xcf_header (SDL_RWops * src) { + xcf_header * h; + xcf_prop prop; + + h = (xcf_header *) malloc (sizeof (xcf_header)); + SDL_RWread (src, h->sign, 14, 1); + h->width = SDL_ReadBE32 (src); + h->height = SDL_ReadBE32 (src); + h->image_type = SDL_ReadBE32 (src); + + h->properties = NULL; + h->compr = COMPR_NONE; + h->cm_num = 0; + h->cm_map = NULL; + + // Just read, don't save + do { + xcf_read_property (src, &prop); + if (prop.id == PROP_COMPRESSION) + h->compr = prop.data.compression; + else if (prop.id == PROP_COLORMAP) { + // unused var: int i; + + h->cm_num = prop.data.colormap.num; + h->cm_map = (unsigned char *) malloc (sizeof (unsigned char) * 3 * h->cm_num); + memcpy (h->cm_map, prop.data.colormap.cmap, 3*sizeof (char)*h->cm_num); + free (prop.data.colormap.cmap); + } + } while (prop.id != PROP_END); + + return h; +} + +static void free_xcf_layer (xcf_layer * l) { + free (l->name); + free (l); +} + +static xcf_layer * read_xcf_layer (SDL_RWops * src) { + xcf_layer * l; + xcf_prop prop; + + l = (xcf_layer *) malloc (sizeof (xcf_layer)); + l->width = SDL_ReadBE32 (src); + l->height = SDL_ReadBE32 (src); + l->layer_type = SDL_ReadBE32 (src); + + l->name = read_string (src); + + do { + xcf_read_property (src, &prop); + if (prop.id == PROP_OFFSETS) { + l->offset_x = prop.data.offset.x; + l->offset_y = prop.data.offset.y; + } else if (prop.id == PROP_VISIBLE) { + l->visible = prop.data.visible ? 1 : 0; + } + } while (prop.id != PROP_END); + + l->hierarchy_file_offset = SDL_ReadBE32 (src); + l->layer_mask_offset = SDL_ReadBE32 (src); + + return l; +} + +static void free_xcf_channel (xcf_channel * c) { + free (c->name); + free (c); +} + +static xcf_channel * read_xcf_channel (SDL_RWops * src) { + xcf_channel * l; + xcf_prop prop; + + l = (xcf_channel *) malloc (sizeof (xcf_channel)); + l->width = SDL_ReadBE32 (src); + l->height = SDL_ReadBE32 (src); + + l->name = read_string (src); + + l->selection = 0; + do { + xcf_read_property (src, &prop); + switch (prop.id) { + case PROP_OPACITY: + l->opacity = prop.data.opacity << 24; + break; + case PROP_COLOR: + l->color = ((Uint32) prop.data.color[0] << 16) + | ((Uint32) prop.data.color[1] << 8) + | ((Uint32) prop.data.color[2]); + break; + case PROP_SELECTION: + l->selection = 1; + break; + case PROP_VISIBLE: + l->visible = prop.data.visible ? 1 : 0; + break; + default: + ; + } + } while (prop.id != PROP_END); + + l->hierarchy_file_offset = SDL_ReadBE32 (src); + + return l; +} + +static void free_xcf_hierarchy (xcf_hierarchy * h) { + free (h->level_file_offsets); + free (h); +} + +static xcf_hierarchy * read_xcf_hierarchy (SDL_RWops * src) { + xcf_hierarchy * h; + int i; + + h = (xcf_hierarchy *) malloc (sizeof (xcf_hierarchy)); + h->width = SDL_ReadBE32 (src); + h->height = SDL_ReadBE32 (src); + h->bpp = SDL_ReadBE32 (src); + + h->level_file_offsets = NULL; + i = 0; + do { + h->level_file_offsets = (Uint32 *) realloc (h->level_file_offsets, sizeof (Uint32) * (i+1)); + h->level_file_offsets [i] = SDL_ReadBE32 (src); + } while (h->level_file_offsets [i++]); + + return h; +} + +static void free_xcf_level (xcf_level * l) { + free (l->tile_file_offsets); + free (l); +} + +static xcf_level * read_xcf_level (SDL_RWops * src) { + xcf_level * l; + int i; + + l = (xcf_level *) malloc (sizeof (xcf_level)); + l->width = SDL_ReadBE32 (src); + l->height = SDL_ReadBE32 (src); + + l->tile_file_offsets = NULL; + i = 0; + do { + l->tile_file_offsets = (Uint32 *) realloc (l->tile_file_offsets, sizeof (Uint32) * (i+1)); + l->tile_file_offsets [i] = SDL_ReadBE32 (src); + } while (l->tile_file_offsets [i++]); + + return l; +} + +static void free_xcf_tile (unsigned char * t) { + free (t); +} + +static unsigned char * load_xcf_tile_none (SDL_RWops * src, Uint32 len, int bpp, int x, int y) { + unsigned char * load; + + load = (unsigned char *) malloc (len); // expect this is okay + SDL_RWread (src, load, len, 1); + + return load; +} + +static unsigned char * load_xcf_tile_rle (SDL_RWops * src, Uint32 len, int bpp, int x, int y) { + unsigned char * load, * t, * data, * d; + Uint32 reallen; + int i, size, count, j, length; + unsigned char val; + + t = load = (unsigned char *) malloc (len); + reallen = SDL_RWread (src, t, 1, len); + + data = (unsigned char *) malloc (x*y*bpp); + for (i = 0; i < bpp; i++) { + d = data + i; + size = x*y; + count = 0; + + while (size > 0) { + val = *t++; + + length = val; + if (length >= 128) { + length = 255 - (length - 1); + if (length == 128) { + length = (*t << 8) + t[1]; + t += 2; + } + + count += length; + size -= length; + + while (length-- > 0) { + *d = *t++; + d += bpp; + } + } + else { + length += 1; + if (length == 128) { + length = (*t << 8) + t[1]; + t += 2; + } + + count += length; + size -= length; + + val = *t++; + + for (j = 0; j < length; j++) { + *d = val; + d += bpp; + } + } + } + } + + free (load); + return (data); +} + +static Uint32 rgb2grey (Uint32 a) { + Uint8 l; + l = 0.2990 * ((a && 0x00FF0000) >> 16) + + 0.5870 * ((a && 0x0000FF00) >> 8) + + 0.1140 * ((a && 0x000000FF)); + + return (l << 16) | (l << 8) | l; +} + +static void create_channel_surface (SDL_Surface * surf, xcf_image_type itype, Uint32 color, Uint32 opacity) { + Uint32 c = 0; + + switch (itype) { + case IMAGE_RGB: + case IMAGE_INDEXED: + c = opacity | color; + break; + case IMAGE_GREYSCALE: + c = opacity | rgb2grey (color); + break; + } + SDL_FillRect (surf, NULL, c); +} + +static int do_layer_surface (SDL_Surface * surface, SDL_RWops * src, xcf_header * head, xcf_layer * layer, load_tile_type load_tile) { + xcf_hierarchy * hierarchy; + xcf_level * level; + unsigned char * tile; + Uint8 * p8; + Uint16 * p16; + Uint32 * p; + int x, y, tx, ty, ox, oy, i, j; + Uint32 *row; + + SDL_RWseek (src, layer->hierarchy_file_offset, RW_SEEK_SET); + hierarchy = read_xcf_hierarchy (src); + + level = NULL; + for (i = 0; hierarchy->level_file_offsets [i]; i++) { + SDL_RWseek (src, hierarchy->level_file_offsets [i], RW_SEEK_SET); + level = read_xcf_level (src); + + ty = tx = 0; + for (j = 0; level->tile_file_offsets [j]; j++) { + SDL_RWseek (src, level->tile_file_offsets [j], RW_SEEK_SET); + ox = tx+64 > level->width ? level->width % 64 : 64; + oy = ty+64 > level->height ? level->height % 64 : 64; + + if (level->tile_file_offsets [j+1]) { + tile = load_tile + (src, + level->tile_file_offsets [j+1] - level->tile_file_offsets [j], + hierarchy->bpp, + ox, oy); + } + else { + tile = load_tile + (src, + ox*oy*6, + hierarchy->bpp, + ox, oy); + } + + p8 = tile; + p16 = (Uint16 *) p8; + p = (Uint32 *) p8; + for (y=ty; y < ty+oy; y++) { + row = (Uint32 *)((Uint8 *)surface->pixels + y*surface->pitch + tx*4); + switch (hierarchy->bpp) { + case 4: + for (x=tx; x < tx+ox; x++) + *row++ = Swap32 (*p++); + break; + case 3: + for (x=tx; x < tx+ox; x++) { + *row = 0xFF000000; + *row |= ((Uint32) *(p8++) << 16); + *row |= ((Uint32) *(p8++) << 8); + *row |= ((Uint32) *(p8++) << 0); + row++; + } + break; + case 2: // Indexed/Greyscale + Alpha + switch (head->image_type) { + case IMAGE_INDEXED: + for (x=tx; x < tx+ox; x++) { + *row = ((Uint32) (head->cm_map [*p8*3]) << 16); + *row |= ((Uint32) (head->cm_map [*p8*3+1]) << 8); + *row |= ((Uint32) (head->cm_map [*p8++*3+2]) << 0); + *row |= ((Uint32) *p8++ << 24);; + row++; + } + break; + case IMAGE_GREYSCALE: + for (x=tx; x < tx+ox; x++) { + *row = ((Uint32) *p8 << 16); + *row |= ((Uint32) *p8 << 8); + *row |= ((Uint32) *p8++ << 0); + *row |= ((Uint32) *p8++ << 24);; + row++; + } + break; + default: + fprintf (stderr, "Unknown Gimp image type (%d)\n", head->image_type); + return 1; + } + break; + case 1: // Indexed/Greyscale + switch (head->image_type) { + case IMAGE_INDEXED: + for (x = tx; x < tx+ox; x++) { + *row++ = 0xFF000000 + | ((Uint32) (head->cm_map [*p8*3]) << 16) + | ((Uint32) (head->cm_map [*p8*3+1]) << 8) + | ((Uint32) (head->cm_map [*p8*3+2]) << 0); + p8++; + } + break; + case IMAGE_GREYSCALE: + for (x=tx; x < tx+ox; x++) { + *row++ = 0xFF000000 + | (((Uint32) (*p8)) << 16) + | (((Uint32) (*p8)) << 8) + | (((Uint32) (*p8)) << 0); + ++p8; + } + break; + default: + fprintf (stderr, "Unknown Gimp image type (%d)\n", head->image_type); + return 1; + } + break; + } + } + tx += 64; + if (tx >= level->width) { + tx = 0; + ty += 64; + } + if (ty >= level->height) { + break; + } + + free_xcf_tile (tile); + } + free_xcf_level (level); + } + + free_xcf_hierarchy (hierarchy); + + return 0; +} + +SDL_Surface *IMG_LoadXCF_RW(SDL_RWops *src) +{ + int start; + const char *error = NULL; + SDL_Surface *surface, *lays; + xcf_header * head; + xcf_layer * layer; + xcf_channel ** channel; + int chnls, i, offsets; + Uint32 offset, fp; + + unsigned char * (* load_tile) (SDL_RWops *, Uint32, int, int, int); + + if ( !src ) { + /* The error message has been set in SDL_RWFromFile */ + return NULL; + } + start = SDL_RWtell(src); + + /* Initialize the data we will clean up when we're done */ + surface = NULL; + + head = read_xcf_header (src); + + switch (head->compr) { + case COMPR_NONE: + load_tile = load_xcf_tile_none; + break; + case COMPR_RLE: + load_tile = load_xcf_tile_rle; + break; + default: + fprintf (stderr, "Unsupported Compression.\n"); + free_xcf_header (head); + return NULL; + } + + /* Create the surface of the appropriate type */ + surface = SDL_AllocSurface(SDL_SWSURFACE, head->width, head->height, 32, + 0x00FF0000,0x0000FF00,0x000000FF,0xFF000000); + + if ( surface == NULL ) { + error = "Out of memory"; + goto done; + } + + head->layer_file_offsets = NULL; + offsets = 0; + + while ((offset = SDL_ReadBE32 (src))) { + head->layer_file_offsets = (Uint32 *) realloc (head->layer_file_offsets, sizeof (Uint32) * (offsets+1)); + head->layer_file_offsets [offsets] = offset; + offsets++; + } + fp = SDL_RWtell (src); + + lays = SDL_AllocSurface(SDL_SWSURFACE, head->width, head->height, 32, + 0x00FF0000,0x0000FF00,0x000000FF,0xFF000000); + + if ( lays == NULL ) { + error = "Out of memory"; + goto done; + } + + // Blit layers backwards, because Gimp saves them highest first + for (i = offsets; i > 0; i--) { + SDL_Rect rs, rd; + SDL_RWseek (src, head->layer_file_offsets [i-1], RW_SEEK_SET); + + layer = read_xcf_layer (src); + do_layer_surface (lays, src, head, layer, load_tile); + rs.x = 0; + rs.y = 0; + rs.w = layer->width; + rs.h = layer->height; + rd.x = layer->offset_x; + rd.y = layer->offset_y; + rd.w = layer->width; + rd.h = layer->height; + + if (layer->visible) + SDL_BlitSurface (lays, &rs, surface, &rd); + free_xcf_layer (layer); + } + + SDL_FreeSurface (lays); + + SDL_RWseek (src, fp, RW_SEEK_SET); + + // read channels + channel = NULL; + chnls = 0; + while ((offset = SDL_ReadBE32 (src))) { + channel = (xcf_channel **) realloc (channel, sizeof (xcf_channel *) * (chnls+1)); + fp = SDL_RWtell (src); + SDL_RWseek (src, offset, RW_SEEK_SET); + channel [chnls++] = (read_xcf_channel (src)); + SDL_RWseek (src, fp, RW_SEEK_SET); + } + + if (chnls) { + SDL_Surface * chs; + + chs = SDL_AllocSurface(SDL_SWSURFACE, head->width, head->height, 32, + 0x00FF0000,0x0000FF00,0x000000FF,0xFF000000); + + if (chs == NULL) { + error = "Out of memory"; + goto done; + } + for (i = 0; i < chnls; i++) { + // printf ("CNLBLT %i\n", i); + if (!channel [i]->selection && channel [i]->visible) { + create_channel_surface (chs, head->image_type, channel [i]->color, channel [i]->opacity); + SDL_BlitSurface (chs, NULL, surface, NULL); + } + free_xcf_channel (channel [i]); + } + + SDL_FreeSurface (chs); + } + +done: + free_xcf_header (head); + if ( error ) { + SDL_RWseek(src, start, RW_SEEK_SET); + if ( surface ) { + SDL_FreeSurface(surface); + surface = NULL; + } + IMG_SetError(error); + } + + return(surface); +} + +#else + +/* See if an image is contained in a data source */ +int IMG_isXCF(SDL_RWops *src) +{ + return(0); +} + +/* Load a XCF type image from an SDL datasource */ +SDL_Surface *IMG_LoadXCF_RW(SDL_RWops *src) +{ + return(NULL); +} + +#endif /* LOAD_XCF */ diff --git a/engines/vileVN/external/SDL/image/IMG_xpm.c b/engines/vileVN/external/SDL/image/IMG_xpm.c new file mode 100644 index 0000000000..486992f459 --- /dev/null +++ b/engines/vileVN/external/SDL/image/IMG_xpm.c @@ -0,0 +1,514 @@ +/* + SDL_image: An example image loading library for use with SDL + Copyright (C) 1997-2012 Sam Lantinga + + 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. +*/ + +/* + * XPM (X PixMap) image loader: + * + * Supports the XPMv3 format, EXCEPT: + * - hotspot coordinates are ignored + * - only colour ('c') colour symbols are used + * - rgb.txt is not used (for portability), so only RGB colours + * are recognized (#rrggbb etc) - only a few basic colour names are + * handled + * + * The result is an 8bpp indexed surface if possible, otherwise 32bpp. + * The colourkey is correctly set if transparency is used. + * + * Besides the standard API, also provides + * + * SDL_Surface *IMG_ReadXPMFromArray(char **xpm) + * + * that reads the image data from an XPM file included in the C source. + * + * TODO: include rgb.txt here. The full table (from solaris 2.6) only + * requires about 13K in binary form. + */ + +#include +#include +#include +#include + +#include "SDL_image.h" + +#ifdef LOAD_XPM + +/* See if an image is contained in a data source */ +int IMG_isXPM(SDL_RWops *src) +{ + int start; + int is_XPM; + char magic[9]; + + if ( !src ) + return 0; + start = SDL_RWtell(src); + is_XPM = 0; + if ( SDL_RWread(src, magic, sizeof(magic), 1) ) { + if ( memcmp(magic, "/* XPM */", sizeof(magic)) == 0 ) { + is_XPM = 1; + } + } + SDL_RWseek(src, start, RW_SEEK_SET); + return(is_XPM); +} + +/* Hash table to look up colors from pixel strings */ +#define STARTING_HASH_SIZE 256 + +struct hash_entry { + char *key; + Uint32 color; + struct hash_entry *next; +}; + +struct color_hash { + struct hash_entry **table; + struct hash_entry *entries; /* array of all entries */ + struct hash_entry *next_free; + int size; + int maxnum; +}; + +static int hash_key(const char *key, int cpp, int size) +{ + int hash; + + hash = 0; + while ( cpp-- > 0 ) { + hash = hash * 33 + *key++; + } + return hash & (size - 1); +} + +static struct color_hash *create_colorhash(int maxnum) +{ + int bytes, s; + struct color_hash *hash; + + /* we know how many entries we need, so we can allocate + everything here */ + hash = malloc(sizeof *hash); + if(!hash) + return NULL; + + /* use power-of-2 sized hash table for decoding speed */ + for(s = STARTING_HASH_SIZE; s < maxnum; s <<= 1) + ; + hash->size = s; + hash->maxnum = maxnum; + bytes = hash->size * sizeof(struct hash_entry **); + hash->entries = NULL; /* in case malloc fails */ + hash->table = malloc(bytes); + if(!hash->table) + return NULL; + memset(hash->table, 0, bytes); + hash->entries = malloc(maxnum * sizeof(struct hash_entry)); + if(!hash->entries) { + free(hash->table); + return NULL; + } + hash->next_free = hash->entries; + return hash; +} + +static int add_colorhash(struct color_hash *hash, + char *key, int cpp, Uint32 color) +{ + int index = hash_key(key, cpp, hash->size); + struct hash_entry *e = hash->next_free++; + e->color = color; + e->key = key; + e->next = hash->table[index]; + hash->table[index] = e; + return 1; +} + +/* fast lookup that works if cpp == 1 */ +#define QUICK_COLORHASH(hash, key) ((hash)->table[*(Uint8 *)(key)]->color) + +static Uint32 get_colorhash(struct color_hash *hash, const char *key, int cpp) +{ + struct hash_entry *entry = hash->table[hash_key(key, cpp, hash->size)]; + while(entry) { + if(memcmp(key, entry->key, cpp) == 0) + return entry->color; + entry = entry->next; + } + return 0; /* garbage in - garbage out */ +} + +static void free_colorhash(struct color_hash *hash) +{ + if(hash && hash->table) { + free(hash->table); + free(hash->entries); + free(hash); + } +} + +/* portable case-insensitive string comparison */ +static int string_equal(const char *a, const char *b, int n) +{ + while(*a && *b && n) { + if(toupper((unsigned char)*a) != toupper((unsigned char)*b)) + return 0; + a++; + b++; + n--; + } + return *a == *b; +} + +#define ARRAYSIZE(a) (int)(sizeof(a) / sizeof((a)[0])) + +/* + * convert colour spec to RGB (in 0xrrggbb format). + * return 1 if successful. + */ +static int color_to_rgb(char *spec, int speclen, Uint32 *rgb) +{ + /* poor man's rgb.txt */ + static struct { char *name; Uint32 rgb; } known[] = { + {"none", 0xffffffff}, + {"black", 0x00000000}, + {"white", 0x00ffffff}, + {"red", 0x00ff0000}, + {"green", 0x0000ff00}, + {"blue", 0x000000ff} + }; + + if(spec[0] == '#') { + char buf[7]; + switch(speclen) { + case 4: + buf[0] = buf[1] = spec[1]; + buf[2] = buf[3] = spec[2]; + buf[4] = buf[5] = spec[3]; + break; + case 7: + memcpy(buf, spec + 1, 6); + break; + case 13: + buf[0] = spec[1]; + buf[1] = spec[2]; + buf[2] = spec[5]; + buf[3] = spec[6]; + buf[4] = spec[9]; + buf[5] = spec[10]; + break; + } + buf[6] = '\0'; + *rgb = strtol(buf, NULL, 16); + return 1; + } else { + int i; + for(i = 0; i < ARRAYSIZE(known); i++) + if(string_equal(known[i].name, spec, speclen)) { + *rgb = known[i].rgb; + return 1; + } + return 0; + } +} + +#ifndef MAX +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#endif + +static char *linebuf; +static int buflen; +static char *error; + +/* + * Read next line from the source. + * If len > 0, it's assumed to be at least len chars (for efficiency). + * Return NULL and set error upon EOF or parse error. + */ +static char *get_next_line(char ***lines, SDL_RWops *src, int len) +{ + char *linebufnew; + + if(lines) { + return *(*lines)++; + } else { + char c; + int n; + do { + if(SDL_RWread(src, &c, 1, 1) <= 0) { + error = "Premature end of data"; + return NULL; + } + } while(c != '"'); + if(len) { + len += 4; /* "\",\n\0" */ + if(len > buflen){ + buflen = len; + linebufnew = realloc(linebuf, buflen); + if(!linebufnew) { + free(linebuf); + error = "Out of memory"; + return NULL; + } + linebuf = linebufnew; + } + if(SDL_RWread(src, linebuf, len - 1, 1) <= 0) { + error = "Premature end of data"; + return NULL; + } + n = len - 2; + } else { + n = 0; + do { + if(n >= buflen - 1) { + if(buflen == 0) + buflen = 16; + buflen *= 2; + linebufnew = realloc(linebuf, buflen); + if(!linebufnew) { + free(linebuf); + error = "Out of memory"; + return NULL; + } + linebuf = linebufnew; + } + if(SDL_RWread(src, linebuf + n, 1, 1) <= 0) { + error = "Premature end of data"; + return NULL; + } + } while(linebuf[n++] != '"'); + n--; + } + linebuf[n] = '\0'; + return linebuf; + } +} + +#define SKIPSPACE(p) \ +do { \ + while(isspace((unsigned char)*(p))) \ + ++(p); \ +} while(0) + +#define SKIPNONSPACE(p) \ +do { \ + while(!isspace((unsigned char)*(p)) && *p) \ + ++(p); \ +} while(0) + +/* read XPM from either array or RWops */ +static SDL_Surface *load_xpm(char **xpm, SDL_RWops *src) +{ + int start = 0; + SDL_Surface *image = NULL; + int index; + int x, y; + int w, h, ncolors, cpp; + int indexed; + Uint8 *dst; + struct color_hash *colors = NULL; + SDL_Color *im_colors = NULL; + char *keystrings = NULL, *nextkey; + char *line; + char ***xpmlines = NULL; + int pixels_len; + + error = NULL; + linebuf = NULL; + buflen = 0; + + if ( src ) + start = SDL_RWtell(src); + + if(xpm) + xpmlines = &xpm; + + line = get_next_line(xpmlines, src, 0); + if(!line) + goto done; + /* + * The header string of an XPMv3 image has the format + * + * [ ] + * + * where the hotspot coords are intended for mouse cursors. + * Right now we don't use the hotspots but it should be handled + * one day. + */ + if(sscanf(line, "%d %d %d %d", &w, &h, &ncolors, &cpp) != 4 + || w <= 0 || h <= 0 || ncolors <= 0 || cpp <= 0) { + error = "Invalid format description"; + goto done; + } + + keystrings = malloc(ncolors * cpp); + if(!keystrings) { + error = "Out of memory"; + goto done; + } + nextkey = keystrings; + + /* Create the new surface */ + if(ncolors <= 256) { + indexed = 1; + image = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 8, + 0, 0, 0, 0); + im_colors = image->format->palette->colors; + image->format->palette->ncolors = ncolors; + } else { + indexed = 0; + image = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 32, + 0xff0000, 0x00ff00, 0x0000ff, 0); + } + if(!image) { + /* Hmm, some SDL error (out of memory?) */ + goto done; + } + + /* Read the colors */ + colors = create_colorhash(ncolors); + if (!colors) { + error = "Out of memory"; + goto done; + } + for(index = 0; index < ncolors; ++index ) { + char *p; + line = get_next_line(xpmlines, src, 0); + if(!line) + goto done; + + p = line + cpp + 1; + + /* parse a colour definition */ + for(;;) { + char nametype; + char *colname; + Uint32 rgb, pixel; + + SKIPSPACE(p); + if(!*p) { + error = "colour parse error"; + goto done; + } + nametype = *p; + SKIPNONSPACE(p); + SKIPSPACE(p); + colname = p; + SKIPNONSPACE(p); + if(nametype == 's') + continue; /* skip symbolic colour names */ + + if(!color_to_rgb(colname, p - colname, &rgb)) + continue; + + memcpy(nextkey, line, cpp); + if(indexed) { + SDL_Color *c = im_colors + index; + c->r = (Uint8)(rgb >> 16); + c->g = (Uint8)(rgb >> 8); + c->b = (Uint8)(rgb); + pixel = index; + } else + pixel = rgb; + add_colorhash(colors, nextkey, cpp, pixel); + nextkey += cpp; + if(rgb == 0xffffffff) + SDL_SetColorKey(image, SDL_SRCCOLORKEY, pixel); + break; + } + } + + /* Read the pixels */ + pixels_len = w * cpp; + dst = image->pixels; + for(y = 0; y < h; y++) { + line = get_next_line(xpmlines, src, pixels_len); + if(indexed) { + /* optimization for some common cases */ + if(cpp == 1) + for(x = 0; x < w; x++) + dst[x] = (Uint8)QUICK_COLORHASH(colors, + line + x); + else + for(x = 0; x < w; x++) + dst[x] = (Uint8)get_colorhash(colors, + line + x * cpp, + cpp); + } else { + for (x = 0; x < w; x++) + ((Uint32*)dst)[x] = get_colorhash(colors, + line + x * cpp, + cpp); + } + dst += image->pitch; + } + +done: + if(error) { + if ( src ) + SDL_RWseek(src, start, RW_SEEK_SET); + if ( image ) { + SDL_FreeSurface(image); + image = NULL; + } + IMG_SetError(error); + } + free(keystrings); + free_colorhash(colors); + free(linebuf); + return(image); +} + +/* Load a XPM type image from an RWops datasource */ +SDL_Surface *IMG_LoadXPM_RW(SDL_RWops *src) +{ + if ( !src ) { + /* The error message has been set in SDL_RWFromFile */ + return NULL; + } + return load_xpm(NULL, src); +} + +SDL_Surface *IMG_ReadXPMFromArray(char **xpm) +{ + return load_xpm(xpm, NULL); +} + +#else /* not LOAD_XPM */ + +/* See if an image is contained in a data source */ +int IMG_isXPM(SDL_RWops *src) +{ + return(0); +} + + +/* Load a XPM type image from an SDL datasource */ +SDL_Surface *IMG_LoadXPM_RW(SDL_RWops *src) +{ + return(NULL); +} + +SDL_Surface *IMG_ReadXPMFromArray(char **xpm) +{ + return NULL; +} +#endif /* not LOAD_XPM */ diff --git a/engines/vileVN/external/SDL/image/IMG_xv.c b/engines/vileVN/external/SDL/image/IMG_xv.c new file mode 100644 index 0000000000..0383ec9fbc --- /dev/null +++ b/engines/vileVN/external/SDL/image/IMG_xv.c @@ -0,0 +1,165 @@ +/* + SDL_image: An example image loading library for use with SDL + Copyright (C) 1997-2012 Sam Lantinga + + 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. +*/ + +/* This is a XV thumbnail image file loading framework */ + +#include +#include + +#include "SDL_image.h" + +#ifdef LOAD_XV + +static int get_line(SDL_RWops *src, char *line, int size) +{ + while ( size > 0 ) { + if ( SDL_RWread(src, line, 1, 1) <= 0 ) { + return -1; + } + if ( *line == '\r' ) { + continue; + } + if ( *line == '\n' ) { + *line = '\0'; + return 0; + } + ++line; + --size; + } + /* Out of space for the line */ + return -1; +} + +static int get_header(SDL_RWops *src, int *w, int *h) +{ + char line[1024]; + + *w = 0; + *h = 0; + + /* Check the header magic */ + if ( (get_line(src, line, sizeof(line)) < 0) || + (memcmp(line, "P7 332", 6) != 0) ) { + return -1; + } + + /* Read the header */ + while ( get_line(src, line, sizeof(line)) == 0 ) { + if ( memcmp(line, "#BUILTIN:", 9) == 0 ) { + /* Builtin image, no data */ + break; + } + if ( memcmp(line, "#END_OF_COMMENTS", 16) == 0 ) { + if ( get_line(src, line, sizeof(line)) == 0 ) { + sscanf(line, "%d %d", w, h); + if ( *w >= 0 && *h >= 0 ) { + return 0; + } + } + break; + } + } + /* No image data */ + return -1; +} + +/* See if an image is contained in a data source */ +int IMG_isXV(SDL_RWops *src) +{ + int start; + int is_XV; + int w, h; + + if ( !src ) + return 0; + start = SDL_RWtell(src); + is_XV = 0; + if ( get_header(src, &w, &h) == 0 ) { + is_XV = 1; + } + SDL_RWseek(src, start, RW_SEEK_SET); + return(is_XV); +} + +/* Load a XV thumbnail image from an SDL datasource */ +SDL_Surface *IMG_LoadXV_RW(SDL_RWops *src) +{ + int start; + const char *error = NULL; + SDL_Surface *surface = NULL; + int w, h; + Uint8 *pixels; + + if ( !src ) { + /* The error message has been set in SDL_RWFromFile */ + return NULL; + } + start = SDL_RWtell(src); + + /* Read the header */ + if ( get_header(src, &w, &h) < 0 ) { + error = "Unsupported image format"; + goto done; + } + + /* Create the 3-3-2 indexed palette surface */ + surface = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 8, 0xe0, 0x1c, 0x03, 0); + if ( surface == NULL ) { + error = "Out of memory"; + goto done; + } + + /* Load the image data */ + for ( pixels = (Uint8 *)surface->pixels; h > 0; --h ) { + if ( SDL_RWread(src, pixels, w, 1) <= 0 ) { + error = "Couldn't read image data"; + goto done; + } + pixels += surface->pitch; + } + +done: + if ( error ) { + SDL_RWseek(src, start, RW_SEEK_SET); + if ( surface ) { + SDL_FreeSurface(surface); + surface = NULL; + } + IMG_SetError(error); + } + return surface; +} + +#else + +/* See if an image is contained in a data source */ +int IMG_isXV(SDL_RWops *src) +{ + return(0); +} + +/* Load a XXX type image from an SDL datasource */ +SDL_Surface *IMG_LoadXV_RW(SDL_RWops *src) +{ + return(NULL); +} + +#endif /* LOAD_XV */ diff --git a/engines/vileVN/external/SDL/image/SDL_image.h b/engines/vileVN/external/SDL/image/SDL_image.h new file mode 100644 index 0000000000..3f07d74a2d --- /dev/null +++ b/engines/vileVN/external/SDL/image/SDL_image.h @@ -0,0 +1,138 @@ +/* + SDL_image: An example image loading library for use with SDL + Copyright (C) 1997-2012 Sam Lantinga + + 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. +*/ + +/* A simple library to load images of various formats as SDL surfaces */ + +#ifndef _SDL_IMAGE_H +#define _SDL_IMAGE_H + +#include "SDL.h" +#include "SDL_version.h" +#include "begin_code.h" + +/* Set up for C function definitions, even when using C++ */ +#ifdef __cplusplus +extern "C" { +#endif + +/* Printable format: "%d.%d.%d", MAJOR, MINOR, PATCHLEVEL +*/ +#define SDL_IMAGE_MAJOR_VERSION 1 +#define SDL_IMAGE_MINOR_VERSION 2 +#define SDL_IMAGE_PATCHLEVEL 12 + +/* This macro can be used to fill a version structure with the compile-time + * version of the SDL_image library. + */ +#define SDL_IMAGE_VERSION(X) \ +{ \ + (X)->major = SDL_IMAGE_MAJOR_VERSION; \ + (X)->minor = SDL_IMAGE_MINOR_VERSION; \ + (X)->patch = SDL_IMAGE_PATCHLEVEL; \ +} + +/* This function gets the version of the dynamically linked SDL_image library. + it should NOT be used to fill a version structure, instead you should + use the SDL_IMAGE_VERSION() macro. + */ +extern DECLSPEC const SDL_version * SDLCALL IMG_Linked_Version(void); + +typedef enum +{ + IMG_INIT_JPG = 0x00000001, + IMG_INIT_PNG = 0x00000002, + IMG_INIT_TIF = 0x00000004, + IMG_INIT_WEBP = 0x00000008 +} IMG_InitFlags; + +/* Loads dynamic libraries and prepares them for use. Flags should be + one or more flags from IMG_InitFlags OR'd together. + It returns the flags successfully initialized, or 0 on failure. + */ +extern DECLSPEC int SDLCALL IMG_Init(int flags); + +/* Unloads libraries loaded with IMG_Init */ +extern DECLSPEC void SDLCALL IMG_Quit(void); + +/* Load an image from an SDL data source. + The 'type' may be one of: "BMP", "GIF", "PNG", etc. + + If the image format supports a transparent pixel, SDL will set the + colorkey for the surface. You can enable RLE acceleration on the + surface afterwards by calling: + SDL_SetColorKey(image, SDL_RLEACCEL, image->format->colorkey); + */ +extern DECLSPEC SDL_Surface * SDLCALL IMG_LoadTyped_RW(SDL_RWops *src, int freesrc, char *type); +/* Convenience functions */ +extern DECLSPEC SDL_Surface * SDLCALL IMG_Load(const char *file); +extern DECLSPEC SDL_Surface * SDLCALL IMG_Load_RW(SDL_RWops *src, int freesrc); + +/* Invert the alpha of a surface for use with OpenGL + This function is now a no-op, and only provided for backwards compatibility. +*/ +extern DECLSPEC int SDLCALL IMG_InvertAlpha(int on); + +/* Functions to detect a file type, given a seekable source */ +extern DECLSPEC int SDLCALL IMG_isICO(SDL_RWops *src); +extern DECLSPEC int SDLCALL IMG_isCUR(SDL_RWops *src); +extern DECLSPEC int SDLCALL IMG_isBMP(SDL_RWops *src); +extern DECLSPEC int SDLCALL IMG_isGIF(SDL_RWops *src); +extern DECLSPEC int SDLCALL IMG_isJPG(SDL_RWops *src); +extern DECLSPEC int SDLCALL IMG_isLBM(SDL_RWops *src); +extern DECLSPEC int SDLCALL IMG_isPCX(SDL_RWops *src); +extern DECLSPEC int SDLCALL IMG_isPNG(SDL_RWops *src); +extern DECLSPEC int SDLCALL IMG_isPNM(SDL_RWops *src); +extern DECLSPEC int SDLCALL IMG_isTIF(SDL_RWops *src); +extern DECLSPEC int SDLCALL IMG_isXCF(SDL_RWops *src); +extern DECLSPEC int SDLCALL IMG_isXPM(SDL_RWops *src); +extern DECLSPEC int SDLCALL IMG_isXV(SDL_RWops *src); +extern DECLSPEC int SDLCALL IMG_isWEBP(SDL_RWops *src); + +/* Individual loading functions */ +extern DECLSPEC SDL_Surface * SDLCALL IMG_LoadICO_RW(SDL_RWops *src); +extern DECLSPEC SDL_Surface * SDLCALL IMG_LoadCUR_RW(SDL_RWops *src); +extern DECLSPEC SDL_Surface * SDLCALL IMG_LoadBMP_RW(SDL_RWops *src); +extern DECLSPEC SDL_Surface * SDLCALL IMG_LoadGIF_RW(SDL_RWops *src); +extern DECLSPEC SDL_Surface * SDLCALL IMG_LoadJPG_RW(SDL_RWops *src); +extern DECLSPEC SDL_Surface * SDLCALL IMG_LoadLBM_RW(SDL_RWops *src); +extern DECLSPEC SDL_Surface * SDLCALL IMG_LoadPCX_RW(SDL_RWops *src); +extern DECLSPEC SDL_Surface * SDLCALL IMG_LoadPNG_RW(SDL_RWops *src); +extern DECLSPEC SDL_Surface * SDLCALL IMG_LoadPNM_RW(SDL_RWops *src); +extern DECLSPEC SDL_Surface * SDLCALL IMG_LoadTGA_RW(SDL_RWops *src); +extern DECLSPEC SDL_Surface * SDLCALL IMG_LoadTIF_RW(SDL_RWops *src); +extern DECLSPEC SDL_Surface * SDLCALL IMG_LoadXCF_RW(SDL_RWops *src); +extern DECLSPEC SDL_Surface * SDLCALL IMG_LoadXPM_RW(SDL_RWops *src); +extern DECLSPEC SDL_Surface * SDLCALL IMG_LoadXV_RW(SDL_RWops *src); +extern DECLSPEC SDL_Surface * SDLCALL IMG_LoadWEBP_RW(SDL_RWops *src); + +extern DECLSPEC SDL_Surface * SDLCALL IMG_ReadXPMFromArray(char **xpm); + +/* We'll use SDL for reporting errors */ +#define IMG_SetError SDL_SetError +#define IMG_GetError SDL_GetError + +/* Ends C function definitions when using C++ */ +#ifdef __cplusplus +} +#endif +#include "close_code.h" + +#endif /* _SDL_IMAGE_H */ diff --git a/engines/vileVN/external/SDL/ttf/SDL_ttf.c b/engines/vileVN/external/SDL/ttf/SDL_ttf.c new file mode 100644 index 0000000000..c2e5d9772d --- /dev/null +++ b/engines/vileVN/external/SDL/ttf/SDL_ttf.c @@ -0,0 +1,2052 @@ +/* + SDL_ttf: A companion library to SDL for working with TrueType (tm) fonts + Copyright (C) 1997-2009 Sam Lantinga + + 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 + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Sam Lantinga + slouken@libsdl.org +*/ + +/* $Id: SDL_ttf.c 5141 2009-10-18 20:47:04Z slouken $ */ + +#include +#include +#include +#include + +#ifdef HAVE_ALLOCA_H +#include +#endif + +#ifdef HAVE_ALLOCA +#define ALLOCA(n) ((void*)alloca(n)) +#define FREEA(p) +#else +#define ALLOCA(n) malloc(n) +#define FREEA(p) free(p) +#endif + +#include +#include FT_FREETYPE_H +#include FT_OUTLINE_H +#include FT_STROKER_H +#include FT_GLYPH_H +#include FT_TRUETYPE_IDS_H + +#include "SDL.h" +#include "SDL_endian.h" +#include "SDL_ttf.h" + +/* FIXME: Right now we assume the gray-scale renderer Freetype is using + supports 256 shades of gray, but we should instead key off of num_grays + in the result FT_Bitmap after the FT_Render_Glyph() call. */ +#define NUM_GRAYS 256 + +/* Handy routines for converting from fixed point */ +#define FT_FLOOR(X) ((X & -64) / 64) +#define FT_CEIL(X) (((X + 63) & -64) / 64) + +#define CACHED_METRICS 0x10 +#define CACHED_BITMAP 0x01 +#define CACHED_PIXMAP 0x02 + +/* Cached glyph information */ +typedef struct cached_glyph { + int stored; + FT_UInt index; + FT_Bitmap bitmap; + FT_Bitmap pixmap; + int minx; + int maxx; + int miny; + int maxy; + int yoffset; + int advance; + Uint16 cached; +} c_glyph; + +/* The structure used to hold internal font information */ +struct _TTF_Font { + /* Freetype2 maintains all sorts of useful info itself */ + FT_Face face; + + /* We'll cache these ourselves */ + int height; + int ascent; + int descent; + int lineskip; + + /* The font style */ + int face_style; + int style; + int outline; + + /* Whether kerning is desired */ + int kerning; + + /* Extra width in glyph bounds for text styles */ + int glyph_overhang; + float glyph_italics; + + /* Information in the font for underlining */ + int underline_offset; + int underline_height; + + /* Cache for style-transformed glyphs */ + c_glyph *current; + c_glyph cache[256]; + c_glyph scratch; + + /* We are responsible for closing the font stream */ + SDL_RWops *src; + int freesrc; + FT_Open_Args args; + + /* For non-scalable formats, we must remember which font index size */ + int font_size_family; + + /* really just flags passed into FT_Load_Glyph */ + int hinting; +}; + +/* Handle a style only if the font does not already handle it */ +#define TTF_HANDLE_STYLE_BOLD(font) (((font)->style & TTF_STYLE_BOLD) && \ + !((font)->face_style & TTF_STYLE_BOLD)) +#define TTF_HANDLE_STYLE_ITALIC(font) (((font)->style & TTF_STYLE_ITALIC) && \ + !((font)->face_style & TTF_STYLE_ITALIC)) +#define TTF_HANDLE_STYLE_UNDERLINE(font) ((font)->style & TTF_STYLE_UNDERLINE) +#define TTF_HANDLE_STYLE_STRIKETHROUGH(font) ((font)->style & TTF_STYLE_STRIKETHROUGH) + +/* Font styles that does not impact glyph drawing */ +#define TTF_STYLE_NO_GLYPH_CHANGE (TTF_STYLE_UNDERLINE | TTF_STYLE_STRIKETHROUGH) + +/* The FreeType font engine/library */ +static FT_Library library; +static int TTF_initialized = 0; +static int TTF_byteswapped = 0; + +/* UNICODE string utilities */ +static __inline__ int UNICODE_strlen(const Uint16 *text) +{ + int size = 0; + while ( *text++ ) { + ++size; + } + return size; +} +static __inline__ void UNICODE_strcpy(Uint16 *dst, const Uint16 *src, int swap) +{ + if ( swap ) { + while ( *src ) { + *dst = SDL_Swap16(*src); + ++src; + ++dst; + } + *dst = '\0'; + } else { + while ( *src ) { + *dst = *src; + ++src; + ++dst; + } + *dst = '\0'; + } +} + +/* Gets the top row of the underline. The outline + is taken into account. +*/ +static __inline__ int TTF_underline_top_row(TTF_Font *font) +{ + /* With outline, the underline_offset is underline_offset+outline. */ + /* So, we don't have to remove the top part of the outline height. */ + return font->ascent - font->underline_offset - 1; +} + +/* Gets the bottom row of the underline. The outline + is taken into account. +*/ +static __inline__ int TTF_underline_bottom_row(TTF_Font *font) +{ + int row = TTF_underline_top_row(font) + font->underline_height; + if( font->outline > 0 ) { + /* Add underline_offset outline offset and */ + /* the bottom part of the outline. */ + row += font->outline * 2; + } + return row; +} + +/* Gets the top row of the strikethrough. The outline + is taken into account. +*/ +static __inline__ int TTF_strikethrough_top_row(TTF_Font *font) +{ + /* With outline, the first text row is 'outline'. */ + /* So, we don't have to remove the top part of the outline height. */ + return font->height / 2; +} + +/* Gets the bottom row of the strikethrough. The outline + is taken into account. +*/ +static __inline__ int TTF_strikethrough_bottom_row(TTF_Font *font) +{ + int row = TTF_strikethrough_top_row(font) + font->underline_height; + if( font->outline > 0 ) { + /* Add first text row outline offset and */ + /* the bottom part of the outline. */ + row += font->outline * 2; + } + return row; +} + +static void TTF_initLineMectrics(const TTF_Font *font, const SDL_Surface *textbuf, const int row, Uint8 **pdst, int *pheight) +{ + Uint8 *dst; + int height; + + dst = (Uint8 *)textbuf->pixels; + if( row > 0 ) { + dst += row * textbuf->pitch; + } + + height = font->underline_height; + /* Take outline into account */ + if( font->outline > 0 ) { + height += font->outline * 2; + } + *pdst = dst; + *pheight = height; +} + +/* Draw a solid line of underline_height (+ optional outline) + at the given row. The row value must take the + outline into account. +*/ +static void TTF_drawLine_Solid(const TTF_Font *font, const SDL_Surface *textbuf, const int row) +{ + int line; + Uint8 *dst_check = (Uint8*)textbuf->pixels + textbuf->pitch * textbuf->h; + Uint8 *dst; + int height; + + TTF_initLineMectrics(font, textbuf, row, &dst, &height); + + /* Draw line */ + for ( line=height; line>0 && dst < dst_check; --line ) { + /* 1 because 0 is the bg color */ + memset( dst, 1, textbuf->w ); + dst += textbuf->pitch; + } +} + +/* Draw a shaded line of underline_height (+ optional outline) + at the given row. The row value must take the + outline into account. +*/ +static void TTF_drawLine_Shaded(const TTF_Font *font, const SDL_Surface *textbuf, const int row) +{ + int line; + Uint8 *dst_check = (Uint8*)textbuf->pixels + textbuf->pitch * textbuf->h; + Uint8 *dst; + int height; + + TTF_initLineMectrics(font, textbuf, row, &dst, &height); + + /* Draw line */ + for ( line=height; line>0 && dst < dst_check; --line ) { + memset( dst, NUM_GRAYS - 1, textbuf->w ); + dst += textbuf->pitch; + } +} + +/* Draw a blended line of underline_height (+ optional outline) + at the given row. The row value must take the + outline into account. +*/ +static void TTF_drawLine_Blended(const TTF_Font *font, const SDL_Surface *textbuf, const int row, const Uint32 color) +{ + int line; + Uint32 *dst_check = (Uint32*)textbuf->pixels + textbuf->pitch/4 * textbuf->h; + Uint8 *dst8; /* destination, byte version */ + Uint32 *dst; + int height; + int col; + Uint32 pixel = color | 0xFF000000; /* Amask */ + + TTF_initLineMectrics(font, textbuf, row, &dst8, &height); + dst = (Uint32 *) dst8; + + /* Draw line */ + for ( line=height; line>0 && dst < dst_check; --line ) { + for ( col=0; col < textbuf->w; ++col ) { + dst[col] = pixel; + } + dst += textbuf->pitch/4; + } +} + +/* rcg06192001 get linked library's version. */ +const SDL_version *TTF_Linked_Version(void) +{ + static SDL_version linked_version; + SDL_TTF_VERSION(&linked_version); + return(&linked_version); +} + +/* This function tells the library whether UNICODE text is generally + byteswapped. A UNICODE BOM character at the beginning of a string + will override this setting for that string. + */ +void TTF_ByteSwappedUNICODE(int swapped) +{ + TTF_byteswapped = swapped; +} + +static void TTF_SetFTError(const char *msg, FT_Error error) +{ +#ifdef USE_FREETYPE_ERRORS +#undef FTERRORS_H +#define FT_ERRORDEF( e, v, s ) { e, s }, + static const struct + { + int err_code; + const char* err_msg; + } ft_errors[] = { +#include + }; + int i; + const char *err_msg; + char buffer[1024]; + + err_msg = NULL; + for ( i=0; i<((sizeof ft_errors)/(sizeof ft_errors[0])); ++i ) { + if ( error == ft_errors[i].err_code ) { + err_msg = ft_errors[i].err_msg; + break; + } + } + if ( ! err_msg ) { + err_msg = "unknown FreeType error"; + } + sprintf(buffer, "%s: %s", msg, err_msg); + TTF_SetError(buffer); +#else + TTF_SetError(msg); +#endif /* USE_FREETYPE_ERRORS */ +} + +int TTF_Init( void ) +{ + int status = 0; + + if ( ! TTF_initialized ) { + FT_Error error = FT_Init_FreeType( &library ); + if ( error ) { + TTF_SetFTError("Couldn't init FreeType engine", error); + status = -1; + } + } + if ( status == 0 ) { + ++TTF_initialized; + } + return status; +} + +static unsigned long RWread( + FT_Stream stream, + unsigned long offset, + unsigned char* buffer, + unsigned long count +) +{ + SDL_RWops *src; + + src = (SDL_RWops *)stream->descriptor.pointer; + SDL_RWseek( src, (int)offset, SEEK_SET ); + if ( count == 0 ) { + return 0; + } + return SDL_RWread( src, buffer, 1, (int)count ); +} + +TTF_Font* TTF_OpenFontIndexRW( SDL_RWops *src, int freesrc, int ptsize, long index ) +{ + TTF_Font* font; + FT_Error error; + FT_Face face; + FT_Fixed scale; + FT_Stream stream; + int position; + + if ( ! TTF_initialized ) { + TTF_SetError( "Library not initialized" ); + return NULL; + } + + /* Check to make sure we can seek in this stream */ + position = SDL_RWtell(src); + if ( position < 0 ) { + TTF_SetError( "Can't seek in stream" ); + return NULL; + } + + font = (TTF_Font*) malloc(sizeof *font); + if ( font == NULL ) { + TTF_SetError( "Out of memory" ); + return NULL; + } + memset(font, 0, sizeof(*font)); + + font->src = src; + font->freesrc = freesrc; + + stream = (FT_Stream)malloc(sizeof(*stream)); + if ( stream == NULL ) { + TTF_SetError( "Out of memory" ); + TTF_CloseFont( font ); + return NULL; + } + memset(stream, 0, sizeof(*stream)); + + stream->read = RWread; + stream->descriptor.pointer = src; + stream->pos = (unsigned long)position; + SDL_RWseek(src, 0, SEEK_END); + stream->size = (unsigned long)(SDL_RWtell(src) - position); + SDL_RWseek(src, position, SEEK_SET); + + font->args.flags = FT_OPEN_STREAM; + font->args.stream = stream; + + error = FT_Open_Face( library, &font->args, index, &font->face ); + if( error ) { + TTF_SetFTError( "Couldn't load font file", error ); + TTF_CloseFont( font ); + return NULL; + } + face = font->face; + + /* Make sure that our font face is scalable (global metrics) */ + if ( FT_IS_SCALABLE(face) ) { + + /* Set the character size and use default DPI (72) */ + error = FT_Set_Char_Size( font->face, 0, ptsize * 64, 0, 0 ); + if( error ) { + TTF_SetFTError( "Couldn't set font size", error ); + TTF_CloseFont( font ); + return NULL; + } + + /* Get the scalable font metrics for this font */ + scale = face->size->metrics.y_scale; + font->ascent = FT_CEIL(FT_MulFix(face->ascender, scale)); + font->descent = FT_CEIL(FT_MulFix(face->descender, scale)); + font->height = font->ascent - font->descent + /* baseline */ 1; + font->lineskip = FT_CEIL(FT_MulFix(face->height, scale)); + font->underline_offset = FT_FLOOR(FT_MulFix(face->underline_position, scale)); + font->underline_height = FT_FLOOR(FT_MulFix(face->underline_thickness, scale)); + + } else { + /* Non-scalable font case. ptsize determines which family + * or series of fonts to grab from the non-scalable format. + * It is not the point size of the font. + * */ + if ( ptsize >= font->face->num_fixed_sizes ) + ptsize = font->face->num_fixed_sizes - 1; + font->font_size_family = ptsize; + error = FT_Set_Pixel_Sizes( face, + face->available_sizes[ptsize].height, + face->available_sizes[ptsize].width ); + /* With non-scalale fonts, Freetype2 likes to fill many of the + * font metrics with the value of 0. The size of the + * non-scalable fonts must be determined differently + * or sometimes cannot be determined. + * */ + font->ascent = face->available_sizes[ptsize].height; + font->descent = 0; + font->height = face->available_sizes[ptsize].height; + font->lineskip = FT_CEIL(font->ascent); + font->underline_offset = FT_FLOOR(face->underline_position); + font->underline_height = FT_FLOOR(face->underline_thickness); + } + + if ( font->underline_height < 1 ) { + font->underline_height = 1; + } + +#ifdef DEBUG_FONTS + printf("Font metrics:\n"); + printf("\tascent = %d, descent = %d\n", + font->ascent, font->descent); + printf("\theight = %d, lineskip = %d\n", + font->height, font->lineskip); + printf("\tunderline_offset = %d, underline_height = %d\n", + font->underline_offset, font->underline_height); + printf("\tunderline_top_row = %d, strikethrough_top_row = %d\n", + TTF_underline_top_row(font), TTF_strikethrough_top_row(font)); +#endif + + /* Initialize the font face style */ + font->face_style = TTF_STYLE_NORMAL; + if ( font->face->style_flags & FT_STYLE_FLAG_BOLD ) { + font->face_style |= TTF_STYLE_BOLD; + } + if ( font->face->style_flags & FT_STYLE_FLAG_ITALIC ) { + font->face_style |= TTF_STYLE_ITALIC; + } + /* Set the default font style */ + font->style = font->face_style; + font->outline = 0; + font->kerning = 1; + font->glyph_overhang = face->size->metrics.y_ppem / 10; + /* x offset = cos(((90.0-12)/360)*2*M_PI), or 12 degree angle */ + font->glyph_italics = 0.207f; + font->glyph_italics *= font->height; + + return font; +} + +TTF_Font* TTF_OpenFontRW( SDL_RWops *src, int freesrc, int ptsize ) +{ + return TTF_OpenFontIndexRW(src, freesrc, ptsize, 0); +} + +TTF_Font* TTF_OpenFontIndex( const char *file, int ptsize, long index ) +{ + SDL_RWops *rw = SDL_RWFromFile(file, "rb"); + if ( rw == NULL ) { + TTF_SetError(SDL_GetError()); + return NULL; + } + return TTF_OpenFontIndexRW(rw, 1, ptsize, index); +} + +TTF_Font* TTF_OpenFont( const char *file, int ptsize ) +{ + return TTF_OpenFontIndex(file, ptsize, 0); +} + +static void Flush_Glyph( c_glyph* glyph ) +{ + glyph->stored = 0; + glyph->index = 0; + if( glyph->bitmap.buffer ) { + free( glyph->bitmap.buffer ); + glyph->bitmap.buffer = 0; + } + if( glyph->pixmap.buffer ) { + free( glyph->pixmap.buffer ); + glyph->pixmap.buffer = 0; + } + glyph->cached = 0; +} + +static void Flush_Cache( TTF_Font* font ) +{ + int i; + int size = sizeof( font->cache ) / sizeof( font->cache[0] ); + + for( i = 0; i < size; ++i ) { + if( font->cache[i].cached ) { + Flush_Glyph( &font->cache[i] ); + } + + } + if( font->scratch.cached ) { + Flush_Glyph( &font->scratch ); + } + +} + +static FT_Error Load_Glyph( TTF_Font* font, Uint16 ch, c_glyph* cached, int want ) +{ + FT_Face face; + FT_Error error; + FT_GlyphSlot glyph; + FT_Glyph_Metrics* metrics; + FT_Outline* outline; + + if ( !font || !font->face ) { + return FT_Err_Invalid_Handle; + } + + face = font->face; + + /* Load the glyph */ + if ( ! cached->index ) { + cached->index = FT_Get_Char_Index( face, ch ); + } + error = FT_Load_Glyph( face, cached->index, FT_LOAD_DEFAULT | font->hinting); + if( error ) { + return error; + } + + /* Get our glyph shortcuts */ + glyph = face->glyph; + metrics = &glyph->metrics; + outline = &glyph->outline; + + /* Get the glyph metrics if desired */ + if ( (want & CACHED_METRICS) && !(cached->stored & CACHED_METRICS) ) { + if ( FT_IS_SCALABLE( face ) ) { + /* Get the bounding box */ + cached->minx = FT_FLOOR(metrics->horiBearingX); + cached->maxx = cached->minx + FT_CEIL(metrics->width); + cached->maxy = FT_FLOOR(metrics->horiBearingY); + cached->miny = cached->maxy - FT_CEIL(metrics->height); + cached->yoffset = font->ascent - cached->maxy; + cached->advance = FT_CEIL(metrics->horiAdvance); + } else { + /* Get the bounding box for non-scalable format. + * Again, freetype2 fills in many of the font metrics + * with the value of 0, so some of the values we + * need must be calculated differently with certain + * assumptions about non-scalable formats. + * */ + cached->minx = FT_FLOOR(metrics->horiBearingX); + cached->maxx = cached->minx + FT_CEIL(metrics->horiAdvance); + cached->maxy = FT_FLOOR(metrics->horiBearingY); + cached->miny = cached->maxy - FT_CEIL(face->available_sizes[font->font_size_family].height); + cached->yoffset = 0; + cached->advance = FT_CEIL(metrics->horiAdvance); + } + + /* Adjust for bold and italic text */ + if( TTF_HANDLE_STYLE_BOLD(font) ) { + cached->maxx += font->glyph_overhang; + } + if( TTF_HANDLE_STYLE_ITALIC(font) ) { + cached->maxx += (int)ceil(font->glyph_italics); + } + cached->stored |= CACHED_METRICS; + } + + if ( ((want & CACHED_BITMAP) && !(cached->stored & CACHED_BITMAP)) || + ((want & CACHED_PIXMAP) && !(cached->stored & CACHED_PIXMAP)) ) { + int mono = (want & CACHED_BITMAP); + int i; + FT_Bitmap* src; + FT_Bitmap* dst; + FT_Glyph bitmap_glyph = NULL; + + /* Handle the italic style */ + if( TTF_HANDLE_STYLE_ITALIC(font) ) { + FT_Matrix shear; + + shear.xx = 1 << 16; + shear.xy = (int) ( font->glyph_italics * ( 1 << 16 ) ) / font->height; + shear.yx = 0; + shear.yy = 1 << 16; + + FT_Outline_Transform( outline, &shear ); + } + + /* Render as outline */ + if( (font->outline > 0) && glyph->format != FT_GLYPH_FORMAT_BITMAP ) { + FT_Stroker stroker; + FT_Get_Glyph( glyph, &bitmap_glyph ); + error = FT_Stroker_New( library, &stroker ); + if( error ) { + return error; + } + FT_Stroker_Set( stroker, font->outline * 64, FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0 ); + FT_Glyph_Stroke( &bitmap_glyph, stroker, 1 /* delete the original glyph */ ); + FT_Stroker_Done( stroker ); + /* Render the glyph */ + error = FT_Glyph_To_Bitmap( &bitmap_glyph, mono ? ft_render_mode_mono : ft_render_mode_normal, 0, 1 ); + if( error ) { + FT_Done_Glyph( bitmap_glyph ); + return error; + } + src = &((FT_BitmapGlyph)bitmap_glyph)->bitmap; + } else { + /* Render the glyph */ + error = FT_Render_Glyph( glyph, mono ? ft_render_mode_mono : ft_render_mode_normal ); + if( error ) { + return error; + } + src = &glyph->bitmap; + } + /* Copy over information to cache */ + if ( mono ) { + dst = &cached->bitmap; + } else { + dst = &cached->pixmap; + } + memcpy( dst, src, sizeof( *dst ) ); + + /* FT_Render_Glyph() and .fon fonts always generate a + * two-color (black and white) glyphslot surface, even + * when rendered in ft_render_mode_normal. */ + /* FT_IS_SCALABLE() means that the font is in outline format, + * but does not imply that outline is rendered as 8-bit + * grayscale, because embedded bitmap/graymap is preferred + * (see FT_LOAD_DEFAULT section of FreeType2 API Reference). + * FT_Render_Glyph() canreturn two-color bitmap or 4/16/256- + * color graymap according to the format of embedded bitmap/ + * graymap. */ + if ( src->pixel_mode == FT_PIXEL_MODE_MONO ) { + dst->pitch *= 8; + } else if ( src->pixel_mode == FT_PIXEL_MODE_GRAY2 ) { + dst->pitch *= 4; + } else if ( src->pixel_mode == FT_PIXEL_MODE_GRAY4 ) { + dst->pitch *= 2; + } + + /* Adjust for bold and italic text */ + if( TTF_HANDLE_STYLE_BOLD(font) ) { + int bump = font->glyph_overhang; + dst->pitch += bump; + dst->width += bump; + } + if( TTF_HANDLE_STYLE_ITALIC(font) ) { + int bump = (int)ceil(font->glyph_italics); + dst->pitch += bump; + dst->width += bump; + } + + if (dst->rows != 0) { + dst->buffer = (unsigned char *)malloc( dst->pitch * dst->rows ); + if( !dst->buffer ) { + return FT_Err_Out_Of_Memory; + } + memset( dst->buffer, 0, dst->pitch * dst->rows ); + + for( i = 0; i < src->rows; i++ ) { + int soffset = i * src->pitch; + int doffset = i * dst->pitch; + if ( mono ) { + unsigned char *srcp = src->buffer + soffset; + unsigned char *dstp = dst->buffer + doffset; + int j; + if ( src->pixel_mode == FT_PIXEL_MODE_MONO ) { + for ( j = 0; j < src->width; j += 8 ) { + unsigned char ch = *srcp++; + *dstp++ = (ch&0x80) >> 7; + ch <<= 1; + *dstp++ = (ch&0x80) >> 7; + ch <<= 1; + *dstp++ = (ch&0x80) >> 7; + ch <<= 1; + *dstp++ = (ch&0x80) >> 7; + ch <<= 1; + *dstp++ = (ch&0x80) >> 7; + ch <<= 1; + *dstp++ = (ch&0x80) >> 7; + ch <<= 1; + *dstp++ = (ch&0x80) >> 7; + ch <<= 1; + *dstp++ = (ch&0x80) >> 7; + } + } else if ( src->pixel_mode == FT_PIXEL_MODE_GRAY2 ) { + for ( j = 0; j < src->width; j += 4 ) { + unsigned char ch = *srcp++; + *dstp++ = (((ch&0xA0) >> 6) >= 0x2) ? 1 : 0; + ch <<= 2; + *dstp++ = (((ch&0xA0) >> 6) >= 0x2) ? 1 : 0; + ch <<= 2; + *dstp++ = (((ch&0xA0) >> 6) >= 0x2) ? 1 : 0; + ch <<= 2; + *dstp++ = (((ch&0xA0) >> 6) >= 0x2) ? 1 : 0; + } + } else if ( src->pixel_mode == FT_PIXEL_MODE_GRAY4 ) { + for ( j = 0; j < src->width; j += 2 ) { + unsigned char ch = *srcp++; + *dstp++ = (((ch&0xF0) >> 4) >= 0x8) ? 1 : 0; + ch <<= 4; + *dstp++ = (((ch&0xF0) >> 4) >= 0x8) ? 1 : 0; + } + } else { + for ( j = 0; j < src->width; j++ ) { + unsigned char ch = *srcp++; + *dstp++ = (ch >= 0x80) ? 1 : 0; + } + } + } else if ( src->pixel_mode == FT_PIXEL_MODE_MONO ) { + /* This special case wouldn't + * be here if the FT_Render_Glyph() + * function wasn't buggy when it tried + * to render a .fon font with 256 + * shades of gray. Instead, it + * returns a black and white surface + * and we have to translate it back + * to a 256 gray shaded surface. + * */ + unsigned char *srcp = src->buffer + soffset; + unsigned char *dstp = dst->buffer + doffset; + unsigned char ch; + int j, k; + for ( j = 0; j < src->width; j += 8) { + ch = *srcp++; + for (k = 0; k < 8; ++k) { + if ((ch&0x80) >> 7) { + *dstp++ = NUM_GRAYS - 1; + } else { + *dstp++ = 0x00; + } + ch <<= 1; + } + } + } else if ( src->pixel_mode == FT_PIXEL_MODE_GRAY2 ) { + unsigned char *srcp = src->buffer + soffset; + unsigned char *dstp = dst->buffer + doffset; + unsigned char ch; + int j, k; + for ( j = 0; j < src->width; j += 4 ) { + ch = *srcp++; + for ( k = 0; k < 4; ++k ) { + if ((ch&0xA0) >> 6) { + *dstp++ = NUM_GRAYS * ((ch&0xA0) >> 6) / 3 - 1; + } else { + *dstp++ = 0x00; + } + ch <<= 2; + } + } + } else if ( src->pixel_mode == FT_PIXEL_MODE_GRAY4 ) { + unsigned char *srcp = src->buffer + soffset; + unsigned char *dstp = dst->buffer + doffset; + unsigned char ch; + int j, k; + for ( j = 0; j < src->width; j += 2 ) { + ch = *srcp++; + for ( k = 0; k < 2; ++k ) { + if ((ch&0xF0) >> 4) { + *dstp++ = NUM_GRAYS * ((ch&0xF0) >> 4) / 15 - 1; + } else { + *dstp++ = 0x00; + } + ch <<= 4; + } + } + } else { + memcpy(dst->buffer+doffset, + src->buffer+soffset, src->pitch); + } + } + } + + /* Handle the bold style */ + if ( TTF_HANDLE_STYLE_BOLD(font) ) { + int row; + int col; + int offset; + int pixel; + Uint8* pixmap; + + /* The pixmap is a little hard, we have to add and clamp */ + for( row = dst->rows - 1; row >= 0; --row ) { + pixmap = (Uint8*) dst->buffer + row * dst->pitch; + for( offset=1; offset <= font->glyph_overhang; ++offset ) { + for( col = dst->width - 1; col > 0; --col ) { + if( mono ) { + pixmap[col] |= pixmap[col-1]; + } else { + pixel = (pixmap[col] + pixmap[col-1]); + if( pixel > NUM_GRAYS - 1 ) { + pixel = NUM_GRAYS - 1; + } + pixmap[col] = (Uint8) pixel; + } + } + } + } + } + + /* Mark that we rendered this format */ + if ( mono ) { + cached->stored |= CACHED_BITMAP; + } else { + cached->stored |= CACHED_PIXMAP; + } + + /* Free outlined glyph */ + if( bitmap_glyph ) { + FT_Done_Glyph( bitmap_glyph ); + } + } + + /* We're done, mark this glyph cached */ + cached->cached = ch; + + return 0; +} + +static FT_Error Find_Glyph( TTF_Font* font, Uint16 ch, int want ) +{ + int retval = 0; + + if( ch < 256 ) { + font->current = &font->cache[ch]; + } else { + if ( font->scratch.cached != ch ) { + Flush_Glyph( &font->scratch ); + } + font->current = &font->scratch; + } + if ( (font->current->stored & want) != want ) { + retval = Load_Glyph( font, ch, font->current, want ); + } + return retval; +} + +void TTF_CloseFont( TTF_Font* font ) +{ + if ( font ) { + Flush_Cache( font ); + if ( font->face ) { + FT_Done_Face( font->face ); + } + if ( font->args.stream ) { + free( font->args.stream ); + } + if ( font->freesrc ) { + SDL_RWclose( font->src ); + } + free( font ); + } +} + +static Uint16 *LATIN1_to_UNICODE(Uint16 *unicode, const char *text, int len) +{ + int i; + + for ( i=0; i < len; ++i ) { + unicode[i] = ((const unsigned char *)text)[i]; + } + unicode[i] = 0; + + return unicode; +} + +static Uint16 *UTF8_to_UNICODE(Uint16 *unicode, const char *utf8, int len) +{ + int i, j; + Uint16 ch; + + for ( i=0, j=0; i < len; ++i, ++j ) { + ch = ((const unsigned char *)utf8)[i]; + if ( ch >= 0xF0 ) { + ch = (Uint16)(utf8[i]&0x07) << 18; + ch |= (Uint16)(utf8[++i]&0x3F) << 12; + ch |= (Uint16)(utf8[++i]&0x3F) << 6; + ch |= (Uint16)(utf8[++i]&0x3F); + } else + if ( ch >= 0xE0 ) { + ch = (Uint16)(utf8[i]&0x0F) << 12; + ch |= (Uint16)(utf8[++i]&0x3F) << 6; + ch |= (Uint16)(utf8[++i]&0x3F); + } else + if ( ch >= 0xC0 ) { + ch = (Uint16)(utf8[i]&0x1F) << 6; + ch |= (Uint16)(utf8[++i]&0x3F); + } + unicode[j] = ch; + } + unicode[j] = 0; + + return unicode; +} + +int TTF_FontHeight(const TTF_Font *font) +{ + return(font->height); +} + +int TTF_FontAscent(const TTF_Font *font) +{ + return(font->ascent); +} + +int TTF_FontDescent(const TTF_Font *font) +{ + return(font->descent); +} + +int TTF_FontLineSkip(const TTF_Font *font) +{ + return(font->lineskip); +} + +int TTF_GetFontKerning(const TTF_Font *font) +{ + return(font->kerning); +} + +void TTF_SetFontKerning(TTF_Font *font, int allowed) +{ + font->kerning = allowed; +} + +long TTF_FontFaces(const TTF_Font *font) +{ + return(font->face->num_faces); +} + +int TTF_FontFaceIsFixedWidth(const TTF_Font *font) +{ + return(FT_IS_FIXED_WIDTH(font->face)); +} + +char *TTF_FontFaceFamilyName(const TTF_Font *font) +{ + return(font->face->family_name); +} + +char *TTF_FontFaceStyleName(const TTF_Font *font) +{ + return(font->face->style_name); +} + +int TTF_GlyphIsProvided(const TTF_Font *font, Uint16 ch) +{ + return(FT_Get_Char_Index(font->face, ch)); +} + +int TTF_GlyphMetrics(TTF_Font *font, Uint16 ch, + int* minx, int* maxx, int* miny, int* maxy, int* advance) +{ + FT_Error error; + + error = Find_Glyph(font, ch, CACHED_METRICS); + if ( error ) { + TTF_SetFTError("Couldn't find glyph", error); + return -1; + } + + if ( minx ) { + *minx = font->current->minx; + } + if ( maxx ) { + *maxx = font->current->maxx; + if( TTF_HANDLE_STYLE_BOLD(font) ) { + *maxx += font->glyph_overhang; + } + } + if ( miny ) { + *miny = font->current->miny; + } + if ( maxy ) { + *maxy = font->current->maxy; + } + if ( advance ) { + *advance = font->current->advance; + if( TTF_HANDLE_STYLE_BOLD(font) ) { + *advance += font->glyph_overhang; + } + } + return 0; +} + +int TTF_SizeText(TTF_Font *font, const char *text, int *w, int *h) +{ + Uint16 *unicode_text; + int unicode_len; + int status; + + /* Copy the Latin-1 text to a UNICODE text buffer */ + unicode_len = strlen(text); + unicode_text = (Uint16 *)ALLOCA((1+unicode_len+1)*(sizeof *unicode_text)); + if ( unicode_text == NULL ) { + TTF_SetError("Out of memory"); + return -1; + } + *unicode_text = UNICODE_BOM_NATIVE; + LATIN1_to_UNICODE(unicode_text+1, text, unicode_len); + + /* Render the new text */ + status = TTF_SizeUNICODE(font, unicode_text, w, h); + + /* Free the text buffer and return */ + FREEA(unicode_text); + return status; +} + +int TTF_SizeUTF8(TTF_Font *font, const char *text, int *w, int *h) +{ + Uint16 *unicode_text; + int unicode_len; + int status; + + /* Copy the UTF-8 text to a UNICODE text buffer */ + unicode_len = strlen(text); + unicode_text = (Uint16 *)ALLOCA((1+unicode_len+1)*(sizeof *unicode_text)); + if ( unicode_text == NULL ) { + TTF_SetError("Out of memory"); + return -1; + } + *unicode_text = UNICODE_BOM_NATIVE; + UTF8_to_UNICODE(unicode_text+1, text, unicode_len); + + /* Render the new text */ + status = TTF_SizeUNICODE(font, unicode_text, w, h); + + /* Free the text buffer and return */ + FREEA(unicode_text); + return status; +} + +int TTF_SizeUNICODE(TTF_Font *font, const Uint16 *text, int *w, int *h) +{ + int status; + const Uint16 *ch; + int swapped; + int x, z; + int minx, maxx; + int miny, maxy; + c_glyph *glyph; + FT_Error error; + FT_Long use_kerning; + FT_UInt prev_index = 0; + int outline_delta = 0; + + /* Initialize everything to 0 */ + if ( ! TTF_initialized ) { + TTF_SetError( "Library not initialized" ); + return -1; + } + status = 0; + minx = maxx = 0; + miny = maxy = 0; + swapped = TTF_byteswapped; + + /* check kerning */ + use_kerning = FT_HAS_KERNING( font->face ) && font->kerning; + + /* Init outline handling */ + if ( font->outline > 0 ) { + outline_delta = font->outline * 2; + } + + /* Load each character and sum it's bounding box */ + x= 0; + for ( ch=text; *ch; ++ch ) { + Uint16 c = *ch; + if ( c == UNICODE_BOM_NATIVE ) { + swapped = 0; + if ( text == ch ) { + ++text; + } + continue; + } + if ( c == UNICODE_BOM_SWAPPED ) { + swapped = 1; + if ( text == ch ) { + ++text; + } + continue; + } + if ( swapped ) { + c = SDL_Swap16(c); + } + + error = Find_Glyph(font, c, CACHED_METRICS); + if ( error ) { + return -1; + } + glyph = font->current; + + /* handle kerning */ + if ( use_kerning && prev_index && glyph->index ) { + FT_Vector delta; + FT_Get_Kerning( font->face, prev_index, glyph->index, ft_kerning_default, &delta ); + x += delta.x >> 6; + } + +#if 0 + if ( (ch == text) && (glyph->minx < 0) ) { + /* Fixes the texture wrapping bug when the first letter + * has a negative minx value or horibearing value. The entire + * bounding box must be adjusted to be bigger so the entire + * letter can fit without any texture corruption or wrapping. + * + * Effects: First enlarges bounding box. + * Second, xstart has to start ahead of its normal spot in the + * negative direction of the negative minx value. + * (pushes everything to the right). + * + * This will make the memory copy of the glyph bitmap data + * work out correctly. + * */ + z -= glyph->minx; + + } +#endif + + z = x + glyph->minx; + if ( minx > z ) { + minx = z; + } + if ( TTF_HANDLE_STYLE_BOLD(font) ) { + x += font->glyph_overhang; + } + if ( glyph->advance > glyph->maxx ) { + z = x + glyph->advance; + } else { + z = x + glyph->maxx; + } + if ( maxx < z ) { + maxx = z; + } + x += glyph->advance; + + if ( glyph->miny < miny ) { + miny = glyph->miny; + } + if ( glyph->maxy > maxy ) { + maxy = glyph->maxy; + } + prev_index = glyph->index; + } + + /* Fill the bounds rectangle */ + if ( w ) { + /* Add outline extra width */ + *w = (maxx - minx) + outline_delta; + } + if ( h ) { + /* Some fonts descend below font height (FletcherGothicFLF) */ + /* Add outline extra height */ + *h = (font->ascent - miny) + outline_delta; + if ( *h < font->height ) { + *h = font->height; + } + /* Update height according to the needs of the underline style */ + if( TTF_HANDLE_STYLE_UNDERLINE(font) ) { + int bottom_row = TTF_underline_bottom_row(font); + if ( *h < bottom_row ) { + *h = bottom_row; + } + } + } + return status; +} + +/* Convert the Latin-1 text to UNICODE and render it +*/ +SDL_Surface *TTF_RenderText_Solid(TTF_Font *font, + const char *text, SDL_Color fg) +{ + SDL_Surface *textbuf; + Uint16 *unicode_text; + int unicode_len; + + /* Copy the Latin-1 text to a UNICODE text buffer */ + unicode_len = strlen(text); + unicode_text = (Uint16 *)ALLOCA((1+unicode_len+1)*(sizeof *unicode_text)); + if ( unicode_text == NULL ) { + TTF_SetError("Out of memory"); + return(NULL); + } + *unicode_text = UNICODE_BOM_NATIVE; + LATIN1_to_UNICODE(unicode_text+1, text, unicode_len); + + /* Render the new text */ + textbuf = TTF_RenderUNICODE_Solid(font, unicode_text, fg); + + /* Free the text buffer and return */ + FREEA(unicode_text); + return(textbuf); +} + +/* Convert the UTF-8 text to UNICODE and render it +*/ +SDL_Surface *TTF_RenderUTF8_Solid(TTF_Font *font, + const char *text, SDL_Color fg) +{ + SDL_Surface *textbuf; + Uint16 *unicode_text; + int unicode_len; + + /* Copy the UTF-8 text to a UNICODE text buffer */ + unicode_len = strlen(text); + unicode_text = (Uint16 *)ALLOCA((1+unicode_len+1)*(sizeof *unicode_text)); + if ( unicode_text == NULL ) { + TTF_SetError("Out of memory"); + return(NULL); + } + *unicode_text = UNICODE_BOM_NATIVE; + UTF8_to_UNICODE(unicode_text, text, unicode_len); + + /* Render the new text */ + textbuf = TTF_RenderUNICODE_Solid(font, unicode_text, fg); + + /* Free the text buffer and return */ + FREEA(unicode_text); + return(textbuf); +} + +SDL_Surface *TTF_RenderUNICODE_Solid(TTF_Font *font, + const Uint16 *text, SDL_Color fg) +{ + int xstart; + int width; + int height; + SDL_Surface* textbuf; + SDL_Palette* palette; + const Uint16* ch; + Uint8* src; + Uint8* dst; + Uint8 *dst_check; + int swapped; + int row, col; + c_glyph *glyph; + + FT_Bitmap *current; + FT_Error error; + FT_Long use_kerning; + FT_UInt prev_index = 0; + + /* Get the dimensions of the text surface */ + if( ( TTF_SizeUNICODE(font, text, &width, &height) < 0 ) || !width ) { + TTF_SetError( "Text has zero width" ); + return NULL; + } + + /* Create the target surface */ + textbuf = SDL_AllocSurface(SDL_SWSURFACE, width, height, 8, 0, 0, 0, 0); + if( textbuf == NULL ) { + return NULL; + } + + /* Adding bound checking to avoid all kinds of memory corruption errors + that may occur. */ + dst_check = (Uint8*)textbuf->pixels + textbuf->pitch * textbuf->h; + + /* Fill the palette with the foreground color */ + palette = textbuf->format->palette; + palette->colors[0].r = 255 - fg.r; + palette->colors[0].g = 255 - fg.g; + palette->colors[0].b = 255 - fg.b; + palette->colors[1].r = fg.r; + palette->colors[1].g = fg.g; + palette->colors[1].b = fg.b; + SDL_SetColorKey( textbuf, SDL_SRCCOLORKEY, 0 ); + + /* check kerning */ + use_kerning = FT_HAS_KERNING( font->face ) && font->kerning; + + /* Load and render each character */ + xstart = 0; + swapped = TTF_byteswapped; + for( ch=text; *ch; ++ch ) { + Uint16 c = *ch; + if ( c == UNICODE_BOM_NATIVE ) { + swapped = 0; + if ( text == ch ) { + ++text; + } + continue; + } + if ( c == UNICODE_BOM_SWAPPED ) { + swapped = 1; + if ( text == ch ) { + ++text; + } + continue; + } + if ( swapped ) { + c = SDL_Swap16(c); + } + + error = Find_Glyph(font, c, CACHED_METRICS|CACHED_BITMAP); + if( error ) { + SDL_FreeSurface( textbuf ); + return NULL; + } + glyph = font->current; + current = &glyph->bitmap; + /* Ensure the width of the pixmap is correct. On some cases, + * freetype may report a larger pixmap than possible.*/ + width = current->width; + if (font->outline <= 0 && width > glyph->maxx - glyph->minx) { + width = glyph->maxx - glyph->minx; + } + /* do kerning, if possible AC-Patch */ + if ( use_kerning && prev_index && glyph->index ) { + FT_Vector delta; + FT_Get_Kerning( font->face, prev_index, glyph->index, ft_kerning_default, &delta ); + xstart += delta.x >> 6; + } + /* Compensate for wrap around bug with negative minx's */ + if ( (ch == text) && (glyph->minx < 0) ) { + xstart -= glyph->minx; + } + + for( row = 0; row < current->rows; ++row ) { + /* Make sure we don't go either over, or under the + * limit */ + if ( row+glyph->yoffset < 0 ) { + continue; + } + if ( row+glyph->yoffset >= textbuf->h ) { + continue; + } + dst = (Uint8*) textbuf->pixels + + (row+glyph->yoffset) * textbuf->pitch + + xstart + glyph->minx; + src = current->buffer + row * current->pitch; + + for ( col=width; col>0 && dst < dst_check; --col ) { + *dst++ |= *src++; + } + } + + xstart += glyph->advance; + if ( TTF_HANDLE_STYLE_BOLD(font) ) { + xstart += font->glyph_overhang; + } + prev_index = glyph->index; + } + + /* Handle the underline style */ + if( TTF_HANDLE_STYLE_UNDERLINE(font) ) { + row = TTF_underline_top_row(font); + TTF_drawLine_Solid(font, textbuf, row); + } + + /* Handle the strikethrough style */ + if( TTF_HANDLE_STYLE_STRIKETHROUGH(font) ) { + row = TTF_strikethrough_top_row(font); + TTF_drawLine_Solid(font, textbuf, row); + } + return textbuf; +} + +SDL_Surface *TTF_RenderGlyph_Solid(TTF_Font *font, Uint16 ch, SDL_Color fg) +{ + SDL_Surface *textbuf; + SDL_Palette *palette; + Uint8 *src, *dst; + int row; + FT_Error error; + c_glyph *glyph; + + /* Get the glyph itself */ + error = Find_Glyph(font, ch, CACHED_METRICS|CACHED_BITMAP); + if ( error ) { + return(NULL); + } + glyph = font->current; + + /* Create the target surface */ + textbuf = SDL_CreateRGBSurface( SDL_SWSURFACE, + glyph->bitmap.pitch, + glyph->bitmap.rows, + 8, 0, 0, 0, 0 ); + if ( ! textbuf ) { + return(NULL); + } + + /* Fill the palette with the foreground color */ + palette = textbuf->format->palette; + palette->colors[0].r = 255-fg.r; + palette->colors[0].g = 255-fg.g; + palette->colors[0].b = 255-fg.b; + palette->colors[1].r = fg.r; + palette->colors[1].g = fg.g; + palette->colors[1].b = fg.b; + SDL_SetColorKey(textbuf, SDL_SRCCOLORKEY, 0); + + /* Copy the character from the pixmap */ + src = glyph->bitmap.buffer; + dst = (Uint8*) textbuf->pixels; + for ( row = 0; row < textbuf->h; ++row ) { + memcpy( dst, src, glyph->bitmap.pitch ); + src += glyph->bitmap.pitch; + dst += textbuf->pitch; + } + + /* Handle the underline style */ + if( TTF_HANDLE_STYLE_UNDERLINE(font) ) { + row = TTF_underline_top_row(font); + TTF_drawLine_Solid(font, textbuf, row); + } + + /* Handle the strikethrough style */ + if( TTF_HANDLE_STYLE_STRIKETHROUGH(font) ) { + row = TTF_strikethrough_top_row(font); + TTF_drawLine_Solid(font, textbuf, row); + } + return(textbuf); +} + + +/* Convert the Latin-1 text to UNICODE and render it +*/ +SDL_Surface *TTF_RenderText_Shaded(TTF_Font *font, + const char *text, SDL_Color fg, SDL_Color bg) +{ + SDL_Surface *textbuf; + Uint16 *unicode_text; + int unicode_len; + + /* Copy the Latin-1 text to a UNICODE text buffer */ + unicode_len = strlen(text); + unicode_text = (Uint16 *)ALLOCA((1+unicode_len+1)*(sizeof *unicode_text)); + if ( unicode_text == NULL ) { + TTF_SetError("Out of memory"); + return(NULL); + } + *unicode_text = UNICODE_BOM_NATIVE; + LATIN1_to_UNICODE(unicode_text+1, text, unicode_len); + + /* Render the new text */ + textbuf = TTF_RenderUNICODE_Shaded(font, unicode_text, fg, bg); + + /* Free the text buffer and return */ + FREEA(unicode_text); + return(textbuf); +} + +/* Convert the UTF-8 text to UNICODE and render it +*/ +SDL_Surface *TTF_RenderUTF8_Shaded(TTF_Font *font, + const char *text, SDL_Color fg, SDL_Color bg) +{ + SDL_Surface *textbuf; + Uint16 *unicode_text; + int unicode_len; + + /* Copy the UTF-8 text to a UNICODE text buffer */ + unicode_len = strlen(text); + unicode_text = (Uint16 *)ALLOCA((1+unicode_len+1)*(sizeof *unicode_text)); + if ( unicode_text == NULL ) { + TTF_SetError("Out of memory"); + return(NULL); + } + *unicode_text = UNICODE_BOM_NATIVE; + UTF8_to_UNICODE(unicode_text+1, text, unicode_len); + + /* Render the new text */ + textbuf = TTF_RenderUNICODE_Shaded(font, unicode_text, fg, bg); + + /* Free the text buffer and return */ + FREEA(unicode_text); + return(textbuf); +} + +SDL_Surface* TTF_RenderUNICODE_Shaded( TTF_Font* font, + const Uint16* text, + SDL_Color fg, + SDL_Color bg ) +{ + int xstart; + int width; + int height; + SDL_Surface* textbuf; + SDL_Palette* palette; + int index; + int rdiff; + int gdiff; + int bdiff; + const Uint16* ch; + Uint8* src; + Uint8* dst; + Uint8* dst_check; + int swapped; + int row, col; + FT_Bitmap* current; + c_glyph *glyph; + FT_Error error; + FT_Long use_kerning; + FT_UInt prev_index = 0; + + /* Get the dimensions of the text surface */ + if( ( TTF_SizeUNICODE(font, text, &width, &height) < 0 ) || !width ) { + TTF_SetError("Text has zero width"); + return NULL; + } + + /* Create the target surface */ + textbuf = SDL_AllocSurface(SDL_SWSURFACE, width, height, 8, 0, 0, 0, 0); + if( textbuf == NULL ) { + return NULL; + } + + /* Adding bound checking to avoid all kinds of memory corruption errors + that may occur. */ + dst_check = (Uint8*)textbuf->pixels + textbuf->pitch * textbuf->h; + + /* Fill the palette with NUM_GRAYS levels of shading from bg to fg */ + palette = textbuf->format->palette; + rdiff = fg.r - bg.r; + gdiff = fg.g - bg.g; + bdiff = fg.b - bg.b; + + for( index = 0; index < NUM_GRAYS; ++index ) { + palette->colors[index].r = bg.r + (index*rdiff) / (NUM_GRAYS-1); + palette->colors[index].g = bg.g + (index*gdiff) / (NUM_GRAYS-1); + palette->colors[index].b = bg.b + (index*bdiff) / (NUM_GRAYS-1); + } + + /* check kerning */ + use_kerning = FT_HAS_KERNING( font->face ) && font->kerning; + + /* Load and render each character */ + xstart = 0; + swapped = TTF_byteswapped; + for( ch = text; *ch; ++ch ) { + Uint16 c = *ch; + if ( c == UNICODE_BOM_NATIVE ) { + swapped = 0; + if ( text == ch ) { + ++text; + } + continue; + } + if ( c == UNICODE_BOM_SWAPPED ) { + swapped = 1; + if ( text == ch ) { + ++text; + } + continue; + } + if ( swapped ) { + c = SDL_Swap16(c); + } + + error = Find_Glyph(font, c, CACHED_METRICS|CACHED_PIXMAP); + if( error ) { + SDL_FreeSurface( textbuf ); + return NULL; + } + glyph = font->current; + /* Ensure the width of the pixmap is correct. On some cases, + * freetype may report a larger pixmap than possible.*/ + width = glyph->pixmap.width; + if (font->outline <= 0 && width > glyph->maxx - glyph->minx) { + width = glyph->maxx - glyph->minx; + } + /* do kerning, if possible AC-Patch */ + if ( use_kerning && prev_index && glyph->index ) { + FT_Vector delta; + FT_Get_Kerning( font->face, prev_index, glyph->index, ft_kerning_default, &delta ); + xstart += delta.x >> 6; + } + /* Compensate for the wrap around with negative minx's */ + if ( (ch == text) && (glyph->minx < 0) ) { + xstart -= glyph->minx; + } + + current = &glyph->pixmap; + for( row = 0; row < current->rows; ++row ) { + /* Make sure we don't go either over, or under the + * limit */ + if ( row+glyph->yoffset < 0 ) { + continue; + } + if ( row+glyph->yoffset >= textbuf->h ) { + continue; + } + dst = (Uint8*) textbuf->pixels + + (row+glyph->yoffset) * textbuf->pitch + + xstart + glyph->minx; + src = current->buffer + row * current->pitch; + for ( col=width; col>0 && dst < dst_check; --col ) { + *dst++ |= *src++; + } + } + + xstart += glyph->advance; + if( TTF_HANDLE_STYLE_BOLD(font) ) { + xstart += font->glyph_overhang; + } + prev_index = glyph->index; + } + + /* Handle the underline style */ + if( TTF_HANDLE_STYLE_UNDERLINE(font) ) { + row = TTF_underline_top_row(font); + TTF_drawLine_Shaded(font, textbuf, row); + } + + /* Handle the strikethrough style */ + if( TTF_HANDLE_STYLE_STRIKETHROUGH(font) ) { + row = TTF_strikethrough_top_row(font); + TTF_drawLine_Shaded(font, textbuf, row); + } + return textbuf; +} + +SDL_Surface* TTF_RenderGlyph_Shaded( TTF_Font* font, + Uint16 ch, + SDL_Color fg, + SDL_Color bg ) +{ + SDL_Surface* textbuf; + SDL_Palette* palette; + int index; + int rdiff; + int gdiff; + int bdiff; + Uint8* src; + Uint8* dst; + int row; + FT_Error error; + c_glyph* glyph; + + /* Get the glyph itself */ + error = Find_Glyph(font, ch, CACHED_METRICS|CACHED_PIXMAP); + if( error ) { + return NULL; + } + glyph = font->current; + + /* Create the target surface */ + textbuf = SDL_CreateRGBSurface( SDL_SWSURFACE, + glyph->pixmap.width, + glyph->pixmap.rows, + 8, 0, 0, 0, 0 ); + if( !textbuf ) { + return NULL; + } + + /* Fill the palette with NUM_GRAYS levels of shading from bg to fg */ + palette = textbuf->format->palette; + rdiff = fg.r - bg.r; + gdiff = fg.g - bg.g; + bdiff = fg.b - bg.b; + for( index = 0; index < NUM_GRAYS; ++index ) { + palette->colors[index].r = bg.r + (index*rdiff) / (NUM_GRAYS-1); + palette->colors[index].g = bg.g + (index*gdiff) / (NUM_GRAYS-1); + palette->colors[index].b = bg.b + (index*bdiff) / (NUM_GRAYS-1); + } + + /* Copy the character from the pixmap */ + src = glyph->pixmap.buffer; + dst = (Uint8*) textbuf->pixels; + for ( row = 0; row < textbuf->h; ++row ) { + memcpy( dst, src, glyph->pixmap.pitch ); + src += glyph->pixmap.pitch; + dst += textbuf->pitch; + } + + /* Handle the underline style */ + if( TTF_HANDLE_STYLE_UNDERLINE(font) ) { + row = TTF_underline_top_row(font); + TTF_drawLine_Shaded(font, textbuf, row); + } + + /* Handle the strikethrough style */ + if( TTF_HANDLE_STYLE_STRIKETHROUGH(font) ) { + row = TTF_strikethrough_top_row(font); + TTF_drawLine_Shaded(font, textbuf, row); + } + return textbuf; +} + +/* Convert the Latin-1 text to UNICODE and render it +*/ +SDL_Surface *TTF_RenderText_Blended(TTF_Font *font, + const char *text, SDL_Color fg) +{ + SDL_Surface *textbuf; + Uint16 *unicode_text; + int unicode_len; + + /* Copy the Latin-1 text to a UNICODE text buffer */ + unicode_len = strlen(text); + unicode_text = (Uint16 *)ALLOCA((1+unicode_len+1)*(sizeof *unicode_text)); + if ( unicode_text == NULL ) { + TTF_SetError("Out of memory"); + return(NULL); + } + *unicode_text = UNICODE_BOM_NATIVE; + LATIN1_to_UNICODE(unicode_text+1, text, unicode_len); + + /* Render the new text */ + textbuf = TTF_RenderUNICODE_Blended(font, unicode_text, fg); + + /* Free the text buffer and return */ + FREEA(unicode_text); + return(textbuf); +} + +/* Convert the UTF-8 text to UNICODE and render it +*/ +SDL_Surface *TTF_RenderUTF8_Blended(TTF_Font *font, + const char *text, SDL_Color fg) +{ + SDL_Surface *textbuf; + Uint16 *unicode_text; + int unicode_len; + + /* Copy the UTF-8 text to a UNICODE text buffer */ + unicode_len = strlen(text); + unicode_text = (Uint16 *)ALLOCA((1+unicode_len+1)*(sizeof *unicode_text)); + if ( unicode_text == NULL ) { + TTF_SetError("Out of memory"); + return(NULL); + } + *unicode_text = UNICODE_BOM_NATIVE; + UTF8_to_UNICODE(unicode_text+1, text, unicode_len); + + /* Render the new text */ + textbuf = TTF_RenderUNICODE_Blended(font, unicode_text, fg); + + /* Free the text buffer and return */ + FREEA(unicode_text); + return(textbuf); +} + +SDL_Surface *TTF_RenderUNICODE_Blended(TTF_Font *font, + const Uint16 *text, SDL_Color fg) +{ + int xstart; + int width, height; + SDL_Surface *textbuf; + Uint32 alpha; + Uint32 pixel; + const Uint16 *ch; + Uint8 *src; + Uint32 *dst; + Uint32 *dst_check; + int swapped; + int row, col; + c_glyph *glyph; + FT_Error error; + FT_Long use_kerning; + FT_UInt prev_index = 0; + + /* Get the dimensions of the text surface */ + if ( (TTF_SizeUNICODE(font, text, &width, &height) < 0) || !width ) { + TTF_SetError("Text has zero width"); + return(NULL); + } + + /* Create the target surface */ + textbuf = SDL_AllocSurface(SDL_SWSURFACE, width, height, 32, + 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000); + if ( textbuf == NULL ) { + return(NULL); + } + + /* Adding bound checking to avoid all kinds of memory corruption errors + that may occur. */ + dst_check = (Uint32*)textbuf->pixels + textbuf->pitch/4 * textbuf->h; + + /* check kerning */ + use_kerning = FT_HAS_KERNING( font->face ) && font->kerning; + + /* Load and render each character */ + xstart = 0; + swapped = TTF_byteswapped; + pixel = (fg.r<<16)|(fg.g<<8)|fg.b; + SDL_FillRect(textbuf, NULL, pixel); /* Initialize with fg and 0 alpha */ + + for ( ch=text; *ch; ++ch ) { + Uint16 c = *ch; + if ( c == UNICODE_BOM_NATIVE ) { + swapped = 0; + if ( text == ch ) { + ++text; + } + continue; + } + if ( c == UNICODE_BOM_SWAPPED ) { + swapped = 1; + if ( text == ch ) { + ++text; + } + continue; + } + if ( swapped ) { + c = SDL_Swap16(c); + } + error = Find_Glyph(font, c, CACHED_METRICS|CACHED_PIXMAP); + if( error ) { + SDL_FreeSurface( textbuf ); + return NULL; + } + glyph = font->current; + /* Ensure the width of the pixmap is correct. On some cases, + * freetype may report a larger pixmap than possible.*/ + width = glyph->pixmap.width; + if (font->outline <= 0 && width > glyph->maxx - glyph->minx) { + width = glyph->maxx - glyph->minx; + } + /* do kerning, if possible AC-Patch */ + if ( use_kerning && prev_index && glyph->index ) { + FT_Vector delta; + FT_Get_Kerning( font->face, prev_index, glyph->index, ft_kerning_default, &delta ); + xstart += delta.x >> 6; + } + + /* Compensate for the wrap around bug with negative minx's */ + if ( (ch == text) && (glyph->minx < 0) ) { + xstart -= glyph->minx; + } + + for ( row = 0; row < glyph->pixmap.rows; ++row ) { + /* Make sure we don't go either over, or under the + * limit */ + if ( row+glyph->yoffset < 0 ) { + continue; + } + if ( row+glyph->yoffset >= textbuf->h ) { + continue; + } + dst = (Uint32*) textbuf->pixels + + (row+glyph->yoffset) * textbuf->pitch/4 + + xstart + glyph->minx; + + /* Added code to adjust src pointer for pixmaps to + * account for pitch. + * */ + src = (Uint8*) (glyph->pixmap.buffer + glyph->pixmap.pitch * row); + for ( col = width; col>0 && dst < dst_check; --col) { + alpha = *src++; + *dst++ |= pixel | (alpha << 24); + } + } + + xstart += glyph->advance; + if ( TTF_HANDLE_STYLE_BOLD(font) ) { + xstart += font->glyph_overhang; + } + prev_index = glyph->index; + } + + /* Handle the underline style */ + if( TTF_HANDLE_STYLE_UNDERLINE(font) ) { + row = TTF_underline_top_row(font); + TTF_drawLine_Blended(font, textbuf, row, pixel); + } + + /* Handle the strikethrough style */ + if( TTF_HANDLE_STYLE_STRIKETHROUGH(font) ) { + row = TTF_strikethrough_top_row(font); + TTF_drawLine_Blended(font, textbuf, row, pixel); + } + return(textbuf); +} + +SDL_Surface *TTF_RenderGlyph_Blended(TTF_Font *font, Uint16 ch, SDL_Color fg) +{ + SDL_Surface *textbuf; + Uint32 alpha; + Uint32 pixel; + Uint8 *src; + Uint32 *dst; + int row, col; + FT_Error error; + c_glyph *glyph; + + /* Get the glyph itself */ + error = Find_Glyph(font, ch, CACHED_METRICS|CACHED_PIXMAP); + if ( error ) { + return(NULL); + } + glyph = font->current; + + textbuf = SDL_CreateRGBSurface(SDL_SWSURFACE, + glyph->pixmap.width, glyph->pixmap.rows, 32, + 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000); + if ( ! textbuf ) { + return(NULL); + } + + /* Copy the character from the pixmap */ + pixel = (fg.r<<16)|(fg.g<<8)|fg.b; + SDL_FillRect(textbuf, NULL, pixel); /* Initialize with fg and 0 alpha */ + + for ( row=0; rowh; ++row ) { + /* Changed src to take pitch into account, not just width */ + src = glyph->pixmap.buffer + row * glyph->pixmap.pitch; + dst = (Uint32 *)textbuf->pixels + row * textbuf->pitch/4; + for ( col=0; colpixmap.width; ++col ) { + alpha = *src++; + *dst++ = pixel | (alpha << 24); + } + } + + /* Handle the underline style */ + if( TTF_HANDLE_STYLE_UNDERLINE(font) ) { + row = TTF_underline_top_row(font); + TTF_drawLine_Blended(font, textbuf, row, pixel); + } + + /* Handle the strikethrough style */ + if( TTF_HANDLE_STYLE_STRIKETHROUGH(font) ) { + row = TTF_strikethrough_top_row(font); + TTF_drawLine_Blended(font, textbuf, row, pixel); + } + return(textbuf); +} + +void TTF_SetFontStyle( TTF_Font* font, int style ) +{ + int prev_style = font->style; + font->style = style | font->face_style; + + /* Flush the cache if the style has changed. + * Ignore UNDERLINE which does not impact glyph drawning. + * */ + if ( (font->style | TTF_STYLE_NO_GLYPH_CHANGE ) != ( prev_style | TTF_STYLE_NO_GLYPH_CHANGE )) { + Flush_Cache( font ); + } +} + +int TTF_GetFontStyle( const TTF_Font* font ) +{ + return font->style; +} + +void TTF_SetFontOutline( TTF_Font* font, int outline ) +{ + font->outline = outline; + Flush_Cache( font ); +} + +int TTF_GetFontOutline( const TTF_Font* font ) +{ + return font->outline; +} + +void TTF_SetFontHinting( TTF_Font* font, int hinting ) +{ + if (hinting == TTF_HINTING_LIGHT) + font->hinting = FT_LOAD_TARGET_LIGHT; + else if (hinting == TTF_HINTING_MONO) + font->hinting = FT_LOAD_TARGET_MONO; + else if (hinting == TTF_HINTING_NONE) + font->hinting = FT_LOAD_NO_HINTING; + else + font->hinting = 0; + Flush_Cache( font ); +} + +int TTF_GetFontHinting( const TTF_Font* font ) +{ + return font->hinting; +} + +void TTF_Quit( void ) +{ + if ( TTF_initialized ) { + if ( --TTF_initialized == 0 ) { + FT_Done_FreeType( library ); + } + } +} + +int TTF_WasInit( void ) +{ + return TTF_initialized; +} diff --git a/engines/vileVN/external/SDL/ttf/SDL_ttf.h b/engines/vileVN/external/SDL/ttf/SDL_ttf.h new file mode 100644 index 0000000000..10433d5981 --- /dev/null +++ b/engines/vileVN/external/SDL/ttf/SDL_ttf.h @@ -0,0 +1,249 @@ +/* + SDL_ttf: A companion library to SDL for working with TrueType (tm) fonts + Copyright (C) 1997-2009 Sam Lantinga + + 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 + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Sam Lantinga + slouken@libsdl.org +*/ + +/* $Id: SDL_ttf.h 5122 2009-10-17 18:16:33Z slouken $ */ + +/* This library is a wrapper around the excellent FreeType 2.0 library, + available at: + http://www.freetype.org/ +*/ + +#ifndef _SDL_TTF_H +#define _SDL_TTF_H + +#include "SDL.h" +#include "begin_code.h" + +/* Set up for C function definitions, even when using C++ */ +#ifdef __cplusplus +extern "C" { +#endif + +/* Printable format: "%d.%d.%d", MAJOR, MINOR, PATCHLEVEL +*/ +#define SDL_TTF_MAJOR_VERSION 2 +#define SDL_TTF_MINOR_VERSION 0 +#define SDL_TTF_PATCHLEVEL 10 + +/* This macro can be used to fill a version structure with the compile-time + * version of the SDL_ttf library. + */ +#define SDL_TTF_VERSION(X) \ +{ \ + (X)->major = SDL_TTF_MAJOR_VERSION; \ + (X)->minor = SDL_TTF_MINOR_VERSION; \ + (X)->patch = SDL_TTF_PATCHLEVEL; \ +} + +/* Backwards compatibility */ +#define TTF_MAJOR_VERSION SDL_TTF_MAJOR_VERSION +#define TTF_MINOR_VERSION SDL_TTF_MINOR_VERSION +#define TTF_PATCHLEVEL SDL_TTF_PATCHLEVEL +#define TTF_VERSION(X) SDL_TTF_VERSION(X) + +/* This function gets the version of the dynamically linked SDL_ttf library. + it should NOT be used to fill a version structure, instead you should + use the SDL_TTF_VERSION() macro. + */ +extern DECLSPEC const SDL_version * SDLCALL TTF_Linked_Version(void); + +/* ZERO WIDTH NO-BREAKSPACE (Unicode byte order mark) */ +#define UNICODE_BOM_NATIVE 0xFEFF +#define UNICODE_BOM_SWAPPED 0xFFFE + +/* This function tells the library whether UNICODE text is generally + byteswapped. A UNICODE BOM character in a string will override + this setting for the remainder of that string. +*/ +extern DECLSPEC void SDLCALL TTF_ByteSwappedUNICODE(int swapped); + +/* The internal structure containing font information */ +typedef struct _TTF_Font TTF_Font; + +/* Initialize the TTF engine - returns 0 if successful, -1 on error */ +extern DECLSPEC int SDLCALL TTF_Init(void); + +/* Open a font file and create a font of the specified point size. + * Some .fon fonts will have several sizes embedded in the file, so the + * point size becomes the index of choosing which size. If the value + * is too high, the last indexed size will be the default. */ +extern DECLSPEC TTF_Font * SDLCALL TTF_OpenFont(const char *file, int ptsize); +extern DECLSPEC TTF_Font * SDLCALL TTF_OpenFontIndex(const char *file, int ptsize, long index); +extern DECLSPEC TTF_Font * SDLCALL TTF_OpenFontRW(SDL_RWops *src, int freesrc, int ptsize); +extern DECLSPEC TTF_Font * SDLCALL TTF_OpenFontIndexRW(SDL_RWops *src, int freesrc, int ptsize, long index); + +/* Set and retrieve the font style */ +#define TTF_STYLE_NORMAL 0x00 +#define TTF_STYLE_BOLD 0x01 +#define TTF_STYLE_ITALIC 0x02 +#define TTF_STYLE_UNDERLINE 0x04 +#define TTF_STYLE_STRIKETHROUGH 0x08 +extern DECLSPEC int SDLCALL TTF_GetFontStyle(const TTF_Font *font); +extern DECLSPEC void SDLCALL TTF_SetFontStyle(TTF_Font *font, int style); +extern DECLSPEC int SDLCALL TTF_GetFontOutline(const TTF_Font *font); +extern DECLSPEC void SDLCALL TTF_SetFontOutline(TTF_Font *font, int outline); + +/* Set and retrieve FreeType hinter settings */ +#define TTF_HINTING_NORMAL 0 +#define TTF_HINTING_LIGHT 1 +#define TTF_HINTING_MONO 2 +#define TTF_HINTING_NONE 3 +extern DECLSPEC int SDLCALL TTF_GetFontHinting(const TTF_Font *font); +extern DECLSPEC void SDLCALL TTF_SetFontHinting(TTF_Font *font, int hinting); + +/* Get the total height of the font - usually equal to point size */ +extern DECLSPEC int SDLCALL TTF_FontHeight(const TTF_Font *font); + +/* Get the offset from the baseline to the top of the font + This is a positive value, relative to the baseline. + */ +extern DECLSPEC int SDLCALL TTF_FontAscent(const TTF_Font *font); + +/* Get the offset from the baseline to the bottom of the font + This is a negative value, relative to the baseline. + */ +extern DECLSPEC int SDLCALL TTF_FontDescent(const TTF_Font *font); + +/* Get the recommended spacing between lines of text for this font */ +extern DECLSPEC int SDLCALL TTF_FontLineSkip(const TTF_Font *font); + +/* Get/Set whether or not kerning is allowed for this font */ +extern DECLSPEC int SDLCALL TTF_GetFontKerning(const TTF_Font *font); +extern DECLSPEC void SDLCALL TTF_SetFontKerning(TTF_Font *font, int allowed); + +/* Get the number of faces of the font */ +extern DECLSPEC long SDLCALL TTF_FontFaces(const TTF_Font *font); + +/* Get the font face attributes, if any */ +extern DECLSPEC int SDLCALL TTF_FontFaceIsFixedWidth(const TTF_Font *font); +extern DECLSPEC char * SDLCALL TTF_FontFaceFamilyName(const TTF_Font *font); +extern DECLSPEC char * SDLCALL TTF_FontFaceStyleName(const TTF_Font *font); + +/* Check wether a glyph is provided by the font or not */ +extern DECLSPEC int SDLCALL TTF_GlyphIsProvided(const TTF_Font *font, Uint16 ch); + +/* Get the metrics (dimensions) of a glyph + To understand what these metrics mean, here is a useful link: + http://freetype.sourceforge.net/freetype2/docs/tutorial/step2.html + */ +extern DECLSPEC int SDLCALL TTF_GlyphMetrics(TTF_Font *font, Uint16 ch, + int *minx, int *maxx, + int *miny, int *maxy, int *advance); + +/* Get the dimensions of a rendered string of text */ +extern DECLSPEC int SDLCALL TTF_SizeText(TTF_Font *font, const char *text, int *w, int *h); +extern DECLSPEC int SDLCALL TTF_SizeUTF8(TTF_Font *font, const char *text, int *w, int *h); +extern DECLSPEC int SDLCALL TTF_SizeUNICODE(TTF_Font *font, const Uint16 *text, int *w, int *h); + +/* Create an 8-bit palettized surface and render the given text at + fast quality with the given font and color. The 0 pixel is the + colorkey, giving a transparent background, and the 1 pixel is set + to the text color. + This function returns the new surface, or NULL if there was an error. +*/ +extern DECLSPEC SDL_Surface * SDLCALL TTF_RenderText_Solid(TTF_Font *font, + const char *text, SDL_Color fg); +extern DECLSPEC SDL_Surface * SDLCALL TTF_RenderUTF8_Solid(TTF_Font *font, + const char *text, SDL_Color fg); +extern DECLSPEC SDL_Surface * SDLCALL TTF_RenderUNICODE_Solid(TTF_Font *font, + const Uint16 *text, SDL_Color fg); + +/* Create an 8-bit palettized surface and render the given glyph at + fast quality with the given font and color. The 0 pixel is the + colorkey, giving a transparent background, and the 1 pixel is set + to the text color. The glyph is rendered without any padding or + centering in the X direction, and aligned normally in the Y direction. + This function returns the new surface, or NULL if there was an error. +*/ +extern DECLSPEC SDL_Surface * SDLCALL TTF_RenderGlyph_Solid(TTF_Font *font, + Uint16 ch, SDL_Color fg); + +/* Create an 8-bit palettized surface and render the given text at + high quality with the given font and colors. The 0 pixel is background, + while other pixels have varying degrees of the foreground color. + This function returns the new surface, or NULL if there was an error. +*/ +extern DECLSPEC SDL_Surface * SDLCALL TTF_RenderText_Shaded(TTF_Font *font, + const char *text, SDL_Color fg, SDL_Color bg); +extern DECLSPEC SDL_Surface * SDLCALL TTF_RenderUTF8_Shaded(TTF_Font *font, + const char *text, SDL_Color fg, SDL_Color bg); +extern DECLSPEC SDL_Surface * SDLCALL TTF_RenderUNICODE_Shaded(TTF_Font *font, + const Uint16 *text, SDL_Color fg, SDL_Color bg); + +/* Create an 8-bit palettized surface and render the given glyph at + high quality with the given font and colors. The 0 pixel is background, + while other pixels have varying degrees of the foreground color. + The glyph is rendered without any padding or centering in the X + direction, and aligned normally in the Y direction. + This function returns the new surface, or NULL if there was an error. +*/ +extern DECLSPEC SDL_Surface * SDLCALL TTF_RenderGlyph_Shaded(TTF_Font *font, + Uint16 ch, SDL_Color fg, SDL_Color bg); + +/* Create a 32-bit ARGB surface and render the given text at high quality, + using alpha blending to dither the font with the given color. + This function returns the new surface, or NULL if there was an error. +*/ +extern DECLSPEC SDL_Surface * SDLCALL TTF_RenderText_Blended(TTF_Font *font, + const char *text, SDL_Color fg); +extern DECLSPEC SDL_Surface * SDLCALL TTF_RenderUTF8_Blended(TTF_Font *font, + const char *text, SDL_Color fg); +extern DECLSPEC SDL_Surface * SDLCALL TTF_RenderUNICODE_Blended(TTF_Font *font, + const Uint16 *text, SDL_Color fg); + +/* Create a 32-bit ARGB surface and render the given glyph at high quality, + using alpha blending to dither the font with the given color. + The glyph is rendered without any padding or centering in the X + direction, and aligned normally in the Y direction. + This function returns the new surface, or NULL if there was an error. +*/ +extern DECLSPEC SDL_Surface * SDLCALL TTF_RenderGlyph_Blended(TTF_Font *font, + Uint16 ch, SDL_Color fg); + +/* For compatibility with previous versions, here are the old functions */ +#define TTF_RenderText(font, text, fg, bg) \ + TTF_RenderText_Shaded(font, text, fg, bg) +#define TTF_RenderUTF8(font, text, fg, bg) \ + TTF_RenderUTF8_Shaded(font, text, fg, bg) +#define TTF_RenderUNICODE(font, text, fg, bg) \ + TTF_RenderUNICODE_Shaded(font, text, fg, bg) + +/* Close an opened font file */ +extern DECLSPEC void SDLCALL TTF_CloseFont(TTF_Font *font); + +/* De-initialize the TTF engine */ +extern DECLSPEC void SDLCALL TTF_Quit(void); + +/* Check if the TTF engine is initialized */ +extern DECLSPEC int SDLCALL TTF_WasInit(void); + +/* We'll use SDL for reporting errors */ +#define TTF_SetError SDL_SetError +#define TTF_GetError SDL_GetError + +/* Ends C function definitions when using C++ */ +#ifdef __cplusplus +} +#endif +#include "close_code.h" + +#endif /* _SDL_TTF_H */ diff --git a/engines/vileVN/external/hq2x/hq2x.cpp b/engines/vileVN/external/hq2x/hq2x.cpp new file mode 100644 index 0000000000..0aa1a436ff --- /dev/null +++ b/engines/vileVN/external/hq2x/hq2x.cpp @@ -0,0 +1,2891 @@ +//hq2x filter demo program +//---------------------------------------------------------- +//Copyright (C) 2003 MaxSt ( maxst@hiend3d.com ) + +//This program is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This program is distributed in the hope that it will be useful, +//but WITHOUT ANY WARRANTY; without even the implied warranty of +//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +//Lesser General Public License for more details. +// +//You should have received a copy of the GNU Lesser General Public +//License along with this program; if not, write to the Free Software +//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +#include +#include +//#include +#include +//#include + +static int LUT16to32[65536]; +static int RGBtoYUV[65536]; +static int YUV1, YUV2; +const int Ymask = 0x00FF0000; +const int Umask = 0x0000FF00; +const int Vmask = 0x000000FF; +const int trY = 0x00300000; +const int trU = 0x00000700; +const int trV = 0x00000006; + +inline void Interp1(unsigned char * pc, int c1, int c2) +{ + *((int*)pc) = (c1*3+c2) >> 2; +} + +inline void Interp2(unsigned char * pc, int c1, int c2, int c3) +{ + *((int*)pc) = (c1*2+c2+c3) >> 2; +} + +inline void Interp5(unsigned char * pc, int c1, int c2) +{ + *((int*)pc) = (c1+c2) >> 1; +} + +inline void Interp6(unsigned char * pc, int c1, int c2, int c3) +{ + //*((int*)pc) = (c1*5+c2*2+c3)/8; + + *((int*)pc) = ((((c1 & 0x00FF00)*5 + (c2 & 0x00FF00)*2 + (c3 & 0x00FF00) ) & 0x0007F800) + + (((c1 & 0xFF00FF)*5 + (c2 & 0xFF00FF)*2 + (c3 & 0xFF00FF) ) & 0x07F807F8)) >> 3; +} + +inline void Interp7(unsigned char * pc, int c1, int c2, int c3) +{ + //*((int*)pc) = (c1*6+c2+c3)/8; + + *((int*)pc) = ((((c1 & 0x00FF00)*6 + (c2 & 0x00FF00) + (c3 & 0x00FF00) ) & 0x0007F800) + + (((c1 & 0xFF00FF)*6 + (c2 & 0xFF00FF) + (c3 & 0xFF00FF) ) & 0x07F807F8)) >> 3; +} + +inline void Interp9(unsigned char * pc, int c1, int c2, int c3) +{ + //*((int*)pc) = (c1*2+(c2+c3)*3)/8; + + *((int*)pc) = ((((c1 & 0x00FF00)*2 + ((c2 & 0x00FF00) + (c3 & 0x00FF00))*3 ) & 0x0007F800) + + (((c1 & 0xFF00FF)*2 + ((c2 & 0xFF00FF) + (c3 & 0xFF00FF))*3 ) & 0x07F807F8)) >> 3; +} + +inline void Interp10(unsigned char * pc, int c1, int c2, int c3) +{ + //*((int*)pc) = (c1*14+c2+c3)/16; + + *((int*)pc) = ((((c1 & 0x00FF00)*14 + (c2 & 0x00FF00) + (c3 & 0x00FF00) ) & 0x000FF000) + + (((c1 & 0xFF00FF)*14 + (c2 & 0xFF00FF) + (c3 & 0xFF00FF) ) & 0x0FF00FF0)) >> 4; +} + + +#define PIXEL00_0 *((int*)(pOut)) = c[5]; +#define PIXEL00_10 Interp1(pOut, c[5], c[1]); +#define PIXEL00_11 Interp1(pOut, c[5], c[4]); +#define PIXEL00_12 Interp1(pOut, c[5], c[2]); +#define PIXEL00_20 Interp2(pOut, c[5], c[4], c[2]); +#define PIXEL00_21 Interp2(pOut, c[5], c[1], c[2]); +#define PIXEL00_22 Interp2(pOut, c[5], c[1], c[4]); +#define PIXEL00_60 Interp6(pOut, c[5], c[2], c[4]); +#define PIXEL00_61 Interp6(pOut, c[5], c[4], c[2]); +#define PIXEL00_70 Interp7(pOut, c[5], c[4], c[2]); +#define PIXEL00_90 Interp9(pOut, c[5], c[4], c[2]); +#define PIXEL00_100 Interp10(pOut, c[5], c[4], c[2]); +#define PIXEL01_0 *((int*)(pOut+4)) = c[5]; +#define PIXEL01_10 Interp1(pOut+4, c[5], c[3]); +#define PIXEL01_11 Interp1(pOut+4, c[5], c[2]); +#define PIXEL01_12 Interp1(pOut+4, c[5], c[6]); +#define PIXEL01_20 Interp2(pOut+4, c[5], c[2], c[6]); +#define PIXEL01_21 Interp2(pOut+4, c[5], c[3], c[6]); +#define PIXEL01_22 Interp2(pOut+4, c[5], c[3], c[2]); +#define PIXEL01_60 Interp6(pOut+4, c[5], c[6], c[2]); +#define PIXEL01_61 Interp6(pOut+4, c[5], c[2], c[6]); +#define PIXEL01_70 Interp7(pOut+4, c[5], c[2], c[6]); +#define PIXEL01_90 Interp9(pOut+4, c[5], c[2], c[6]); +#define PIXEL01_100 Interp10(pOut+4, c[5], c[2], c[6]); +#define PIXEL10_0 *((int*)(pOut+BpL)) = c[5]; +#define PIXEL10_10 Interp1(pOut+BpL, c[5], c[7]); +#define PIXEL10_11 Interp1(pOut+BpL, c[5], c[8]); +#define PIXEL10_12 Interp1(pOut+BpL, c[5], c[4]); +#define PIXEL10_20 Interp2(pOut+BpL, c[5], c[8], c[4]); +#define PIXEL10_21 Interp2(pOut+BpL, c[5], c[7], c[4]); +#define PIXEL10_22 Interp2(pOut+BpL, c[5], c[7], c[8]); +#define PIXEL10_60 Interp6(pOut+BpL, c[5], c[4], c[8]); +#define PIXEL10_61 Interp6(pOut+BpL, c[5], c[8], c[4]); +#define PIXEL10_70 Interp7(pOut+BpL, c[5], c[8], c[4]); +#define PIXEL10_90 Interp9(pOut+BpL, c[5], c[8], c[4]); +#define PIXEL10_100 Interp10(pOut+BpL, c[5], c[8], c[4]); +#define PIXEL11_0 *((int*)(pOut+BpL+4)) = c[5]; +#define PIXEL11_10 Interp1(pOut+BpL+4, c[5], c[9]); +#define PIXEL11_11 Interp1(pOut+BpL+4, c[5], c[6]); +#define PIXEL11_12 Interp1(pOut+BpL+4, c[5], c[8]); +#define PIXEL11_20 Interp2(pOut+BpL+4, c[5], c[6], c[8]); +#define PIXEL11_21 Interp2(pOut+BpL+4, c[5], c[9], c[8]); +#define PIXEL11_22 Interp2(pOut+BpL+4, c[5], c[9], c[6]); +#define PIXEL11_60 Interp6(pOut+BpL+4, c[5], c[8], c[6]); +#define PIXEL11_61 Interp6(pOut+BpL+4, c[5], c[6], c[8]); +#define PIXEL11_70 Interp7(pOut+BpL+4, c[5], c[6], c[8]); +#define PIXEL11_90 Interp9(pOut+BpL+4, c[5], c[6], c[8]); +#define PIXEL11_100 Interp10(pOut+BpL+4, c[5], c[6], c[8]); + + + +inline bool Diff(unsigned int w1, unsigned int w2) +{ + YUV1 = RGBtoYUV[w1]; + YUV2 = RGBtoYUV[w2]; + return ( ( abs((YUV1 & Ymask) - (YUV2 & Ymask)) > trY ) || + ( abs((YUV1 & Umask) - (YUV2 & Umask)) > trU ) || + ( abs((YUV1 & Vmask) - (YUV2 & Vmask)) > trV ) ); +} + +void hq2x_32( unsigned char * pIn, unsigned char * pOut, int Xres, int Yres, int BpL ) +{ + int i, j, k; + int prevline, nextline; + int w[10]; + int c[10]; + + // +----+----+----+ + // | | | | + // | w1 | w2 | w3 | + // +----+----+----+ + // | | | | + // | w4 | w5 | w6 | + // +----+----+----+ + // | | | | + // | w7 | w8 | w9 | + // +----+----+----+ + + for (j=0; j0) prevline = -Xres*2; else prevline = 0; + if (j0) + { + w[1] = *((unsigned short*)(pIn + prevline - 2)); + w[4] = *((unsigned short*)(pIn - 2)); + w[7] = *((unsigned short*)(pIn + nextline - 2)); + } + else + { + w[1] = w[2]; + w[4] = w[5]; + w[7] = w[8]; + } + + if (i trY ) || + ( abs((YUV1 & Umask) - (YUV2 & Umask)) > trU ) || + ( abs((YUV1 & Vmask) - (YUV2 & Vmask)) > trV ) ) + pattern |= flag; + } + flag <<= 1; + } + + for (k=1; k<=9; k++) + c[k] = LUT16to32[w[k]]; + + switch (pattern) + { + case 0: + case 1: + case 4: + case 32: + case 128: + case 5: + case 132: + case 160: + case 33: + case 129: + case 36: + case 133: + case 164: + case 161: + case 37: + case 165: + { + PIXEL00_20 + PIXEL01_20 + PIXEL10_20 + PIXEL11_20 + break; + } + case 2: + case 34: + case 130: + case 162: + { + PIXEL00_22 + PIXEL01_21 + PIXEL10_20 + PIXEL11_20 + break; + } + case 16: + case 17: + case 48: + case 49: + { + PIXEL00_20 + PIXEL01_22 + PIXEL10_20 + PIXEL11_21 + break; + } + case 64: + case 65: + case 68: + case 69: + { + PIXEL00_20 + PIXEL01_20 + PIXEL10_21 + PIXEL11_22 + break; + } + case 8: + case 12: + case 136: + case 140: + { + PIXEL00_21 + PIXEL01_20 + PIXEL10_22 + PIXEL11_20 + break; + } + case 3: + case 35: + case 131: + case 163: + { + PIXEL00_11 + PIXEL01_21 + PIXEL10_20 + PIXEL11_20 + break; + } + case 6: + case 38: + case 134: + case 166: + { + PIXEL00_22 + PIXEL01_12 + PIXEL10_20 + PIXEL11_20 + break; + } + case 20: + case 21: + case 52: + case 53: + { + PIXEL00_20 + PIXEL01_11 + PIXEL10_20 + PIXEL11_21 + break; + } + case 144: + case 145: + case 176: + case 177: + { + PIXEL00_20 + PIXEL01_22 + PIXEL10_20 + PIXEL11_12 + break; + } + case 192: + case 193: + case 196: + case 197: + { + PIXEL00_20 + PIXEL01_20 + PIXEL10_21 + PIXEL11_11 + break; + } + case 96: + case 97: + case 100: + case 101: + { + PIXEL00_20 + PIXEL01_20 + PIXEL10_12 + PIXEL11_22 + break; + } + case 40: + case 44: + case 168: + case 172: + { + PIXEL00_21 + PIXEL01_20 + PIXEL10_11 + PIXEL11_20 + break; + } + case 9: + case 13: + case 137: + case 141: + { + PIXEL00_12 + PIXEL01_20 + PIXEL10_22 + PIXEL11_20 + break; + } + case 18: + case 50: + { + PIXEL00_22 + if (Diff(w[2], w[6])) + { + PIXEL01_10 + } + else + { + PIXEL01_20 + } + PIXEL10_20 + PIXEL11_21 + break; + } + case 80: + case 81: + { + PIXEL00_20 + PIXEL01_22 + PIXEL10_21 + if (Diff(w[6], w[8])) + { + PIXEL11_10 + } + else + { + PIXEL11_20 + } + break; + } + case 72: + case 76: + { + PIXEL00_21 + PIXEL01_20 + if (Diff(w[8], w[4])) + { + PIXEL10_10 + } + else + { + PIXEL10_20 + } + PIXEL11_22 + break; + } + case 10: + case 138: + { + if (Diff(w[4], w[2])) + { + PIXEL00_10 + } + else + { + PIXEL00_20 + } + PIXEL01_21 + PIXEL10_22 + PIXEL11_20 + break; + } + case 66: + { + PIXEL00_22 + PIXEL01_21 + PIXEL10_21 + PIXEL11_22 + break; + } + case 24: + { + PIXEL00_21 + PIXEL01_22 + PIXEL10_22 + PIXEL11_21 + break; + } + case 7: + case 39: + case 135: + { + PIXEL00_11 + PIXEL01_12 + PIXEL10_20 + PIXEL11_20 + break; + } + case 148: + case 149: + case 180: + { + PIXEL00_20 + PIXEL01_11 + PIXEL10_20 + PIXEL11_12 + break; + } + case 224: + case 228: + case 225: + { + PIXEL00_20 + PIXEL01_20 + PIXEL10_12 + PIXEL11_11 + break; + } + case 41: + case 169: + case 45: + { + PIXEL00_12 + PIXEL01_20 + PIXEL10_11 + PIXEL11_20 + break; + } + case 22: + case 54: + { + PIXEL00_22 + if (Diff(w[2], w[6])) + { + PIXEL01_0 + } + else + { + PIXEL01_20 + } + PIXEL10_20 + PIXEL11_21 + break; + } + case 208: + case 209: + { + PIXEL00_20 + PIXEL01_22 + PIXEL10_21 + if (Diff(w[6], w[8])) + { + PIXEL11_0 + } + else + { + PIXEL11_20 + } + break; + } + case 104: + case 108: + { + PIXEL00_21 + PIXEL01_20 + if (Diff(w[8], w[4])) + { + PIXEL10_0 + } + else + { + PIXEL10_20 + } + PIXEL11_22 + break; + } + case 11: + case 139: + { + if (Diff(w[4], w[2])) + { + PIXEL00_0 + } + else + { + PIXEL00_20 + } + PIXEL01_21 + PIXEL10_22 + PIXEL11_20 + break; + } + case 19: + case 51: + { + if (Diff(w[2], w[6])) + { + PIXEL00_11 + PIXEL01_10 + } + else + { + PIXEL00_60 + PIXEL01_90 + } + PIXEL10_20 + PIXEL11_21 + break; + } + case 146: + case 178: + { + PIXEL00_22 + if (Diff(w[2], w[6])) + { + PIXEL01_10 + PIXEL11_12 + } + else + { + PIXEL01_90 + PIXEL11_61 + } + PIXEL10_20 + break; + } + case 84: + case 85: + { + PIXEL00_20 + if (Diff(w[6], w[8])) + { + PIXEL01_11 + PIXEL11_10 + } + else + { + PIXEL01_60 + PIXEL11_90 + } + PIXEL10_21 + break; + } + case 112: + case 113: + { + PIXEL00_20 + PIXEL01_22 + if (Diff(w[6], w[8])) + { + PIXEL10_12 + PIXEL11_10 + } + else + { + PIXEL10_61 + PIXEL11_90 + } + break; + } + case 200: + case 204: + { + PIXEL00_21 + PIXEL01_20 + if (Diff(w[8], w[4])) + { + PIXEL10_10 + PIXEL11_11 + } + else + { + PIXEL10_90 + PIXEL11_60 + } + break; + } + case 73: + case 77: + { + if (Diff(w[8], w[4])) + { + PIXEL00_12 + PIXEL10_10 + } + else + { + PIXEL00_61 + PIXEL10_90 + } + PIXEL01_20 + PIXEL11_22 + break; + } + case 42: + case 170: + { + if (Diff(w[4], w[2])) + { + PIXEL00_10 + PIXEL10_11 + } + else + { + PIXEL00_90 + PIXEL10_60 + } + PIXEL01_21 + PIXEL11_20 + break; + } + case 14: + case 142: + { + if (Diff(w[4], w[2])) + { + PIXEL00_10 + PIXEL01_12 + } + else + { + PIXEL00_90 + PIXEL01_61 + } + PIXEL10_22 + PIXEL11_20 + break; + } + case 67: + { + PIXEL00_11 + PIXEL01_21 + PIXEL10_21 + PIXEL11_22 + break; + } + case 70: + { + PIXEL00_22 + PIXEL01_12 + PIXEL10_21 + PIXEL11_22 + break; + } + case 28: + { + PIXEL00_21 + PIXEL01_11 + PIXEL10_22 + PIXEL11_21 + break; + } + case 152: + { + PIXEL00_21 + PIXEL01_22 + PIXEL10_22 + PIXEL11_12 + break; + } + case 194: + { + PIXEL00_22 + PIXEL01_21 + PIXEL10_21 + PIXEL11_11 + break; + } + case 98: + { + PIXEL00_22 + PIXEL01_21 + PIXEL10_12 + PIXEL11_22 + break; + } + case 56: + { + PIXEL00_21 + PIXEL01_22 + PIXEL10_11 + PIXEL11_21 + break; + } + case 25: + { + PIXEL00_12 + PIXEL01_22 + PIXEL10_22 + PIXEL11_21 + break; + } + case 26: + case 31: + { + if (Diff(w[4], w[2])) + { + PIXEL00_0 + } + else + { + PIXEL00_20 + } + if (Diff(w[2], w[6])) + { + PIXEL01_0 + } + else + { + PIXEL01_20 + } + PIXEL10_22 + PIXEL11_21 + break; + } + case 82: + case 214: + { + PIXEL00_22 + if (Diff(w[2], w[6])) + { + PIXEL01_0 + } + else + { + PIXEL01_20 + } + PIXEL10_21 + if (Diff(w[6], w[8])) + { + PIXEL11_0 + } + else + { + PIXEL11_20 + } + break; + } + case 88: + case 248: + { + PIXEL00_21 + PIXEL01_22 + if (Diff(w[8], w[4])) + { + PIXEL10_0 + } + else + { + PIXEL10_20 + } + if (Diff(w[6], w[8])) + { + PIXEL11_0 + } + else + { + PIXEL11_20 + } + break; + } + case 74: + case 107: + { + if (Diff(w[4], w[2])) + { + PIXEL00_0 + } + else + { + PIXEL00_20 + } + PIXEL01_21 + if (Diff(w[8], w[4])) + { + PIXEL10_0 + } + else + { + PIXEL10_20 + } + PIXEL11_22 + break; + } + case 27: + { + if (Diff(w[4], w[2])) + { + PIXEL00_0 + } + else + { + PIXEL00_20 + } + PIXEL01_10 + PIXEL10_22 + PIXEL11_21 + break; + } + case 86: + { + PIXEL00_22 + if (Diff(w[2], w[6])) + { + PIXEL01_0 + } + else + { + PIXEL01_20 + } + PIXEL10_21 + PIXEL11_10 + break; + } + case 216: + { + PIXEL00_21 + PIXEL01_22 + PIXEL10_10 + if (Diff(w[6], w[8])) + { + PIXEL11_0 + } + else + { + PIXEL11_20 + } + break; + } + case 106: + { + PIXEL00_10 + PIXEL01_21 + if (Diff(w[8], w[4])) + { + PIXEL10_0 + } + else + { + PIXEL10_20 + } + PIXEL11_22 + break; + } + case 30: + { + PIXEL00_10 + if (Diff(w[2], w[6])) + { + PIXEL01_0 + } + else + { + PIXEL01_20 + } + PIXEL10_22 + PIXEL11_21 + break; + } + case 210: + { + PIXEL00_22 + PIXEL01_10 + PIXEL10_21 + if (Diff(w[6], w[8])) + { + PIXEL11_0 + } + else + { + PIXEL11_20 + } + break; + } + case 120: + { + PIXEL00_21 + PIXEL01_22 + if (Diff(w[8], w[4])) + { + PIXEL10_0 + } + else + { + PIXEL10_20 + } + PIXEL11_10 + break; + } + case 75: + { + if (Diff(w[4], w[2])) + { + PIXEL00_0 + } + else + { + PIXEL00_20 + } + PIXEL01_21 + PIXEL10_10 + PIXEL11_22 + break; + } + case 29: + { + PIXEL00_12 + PIXEL01_11 + PIXEL10_22 + PIXEL11_21 + break; + } + case 198: + { + PIXEL00_22 + PIXEL01_12 + PIXEL10_21 + PIXEL11_11 + break; + } + case 184: + { + PIXEL00_21 + PIXEL01_22 + PIXEL10_11 + PIXEL11_12 + break; + } + case 99: + { + PIXEL00_11 + PIXEL01_21 + PIXEL10_12 + PIXEL11_22 + break; + } + case 57: + { + PIXEL00_12 + PIXEL01_22 + PIXEL10_11 + PIXEL11_21 + break; + } + case 71: + { + PIXEL00_11 + PIXEL01_12 + PIXEL10_21 + PIXEL11_22 + break; + } + case 156: + { + PIXEL00_21 + PIXEL01_11 + PIXEL10_22 + PIXEL11_12 + break; + } + case 226: + { + PIXEL00_22 + PIXEL01_21 + PIXEL10_12 + PIXEL11_11 + break; + } + case 60: + { + PIXEL00_21 + PIXEL01_11 + PIXEL10_11 + PIXEL11_21 + break; + } + case 195: + { + PIXEL00_11 + PIXEL01_21 + PIXEL10_21 + PIXEL11_11 + break; + } + case 102: + { + PIXEL00_22 + PIXEL01_12 + PIXEL10_12 + PIXEL11_22 + break; + } + case 153: + { + PIXEL00_12 + PIXEL01_22 + PIXEL10_22 + PIXEL11_12 + break; + } + case 58: + { + if (Diff(w[4], w[2])) + { + PIXEL00_10 + } + else + { + PIXEL00_70 + } + if (Diff(w[2], w[6])) + { + PIXEL01_10 + } + else + { + PIXEL01_70 + } + PIXEL10_11 + PIXEL11_21 + break; + } + case 83: + { + PIXEL00_11 + if (Diff(w[2], w[6])) + { + PIXEL01_10 + } + else + { + PIXEL01_70 + } + PIXEL10_21 + if (Diff(w[6], w[8])) + { + PIXEL11_10 + } + else + { + PIXEL11_70 + } + break; + } + case 92: + { + PIXEL00_21 + PIXEL01_11 + if (Diff(w[8], w[4])) + { + PIXEL10_10 + } + else + { + PIXEL10_70 + } + if (Diff(w[6], w[8])) + { + PIXEL11_10 + } + else + { + PIXEL11_70 + } + break; + } + case 202: + { + if (Diff(w[4], w[2])) + { + PIXEL00_10 + } + else + { + PIXEL00_70 + } + PIXEL01_21 + if (Diff(w[8], w[4])) + { + PIXEL10_10 + } + else + { + PIXEL10_70 + } + PIXEL11_11 + break; + } + case 78: + { + if (Diff(w[4], w[2])) + { + PIXEL00_10 + } + else + { + PIXEL00_70 + } + PIXEL01_12 + if (Diff(w[8], w[4])) + { + PIXEL10_10 + } + else + { + PIXEL10_70 + } + PIXEL11_22 + break; + } + case 154: + { + if (Diff(w[4], w[2])) + { + PIXEL00_10 + } + else + { + PIXEL00_70 + } + if (Diff(w[2], w[6])) + { + PIXEL01_10 + } + else + { + PIXEL01_70 + } + PIXEL10_22 + PIXEL11_12 + break; + } + case 114: + { + PIXEL00_22 + if (Diff(w[2], w[6])) + { + PIXEL01_10 + } + else + { + PIXEL01_70 + } + PIXEL10_12 + if (Diff(w[6], w[8])) + { + PIXEL11_10 + } + else + { + PIXEL11_70 + } + break; + } + case 89: + { + PIXEL00_12 + PIXEL01_22 + if (Diff(w[8], w[4])) + { + PIXEL10_10 + } + else + { + PIXEL10_70 + } + if (Diff(w[6], w[8])) + { + PIXEL11_10 + } + else + { + PIXEL11_70 + } + break; + } + case 90: + { + if (Diff(w[4], w[2])) + { + PIXEL00_10 + } + else + { + PIXEL00_70 + } + if (Diff(w[2], w[6])) + { + PIXEL01_10 + } + else + { + PIXEL01_70 + } + if (Diff(w[8], w[4])) + { + PIXEL10_10 + } + else + { + PIXEL10_70 + } + if (Diff(w[6], w[8])) + { + PIXEL11_10 + } + else + { + PIXEL11_70 + } + break; + } + case 55: + case 23: + { + if (Diff(w[2], w[6])) + { + PIXEL00_11 + PIXEL01_0 + } + else + { + PIXEL00_60 + PIXEL01_90 + } + PIXEL10_20 + PIXEL11_21 + break; + } + case 182: + case 150: + { + PIXEL00_22 + if (Diff(w[2], w[6])) + { + PIXEL01_0 + PIXEL11_12 + } + else + { + PIXEL01_90 + PIXEL11_61 + } + PIXEL10_20 + break; + } + case 213: + case 212: + { + PIXEL00_20 + if (Diff(w[6], w[8])) + { + PIXEL01_11 + PIXEL11_0 + } + else + { + PIXEL01_60 + PIXEL11_90 + } + PIXEL10_21 + break; + } + case 241: + case 240: + { + PIXEL00_20 + PIXEL01_22 + if (Diff(w[6], w[8])) + { + PIXEL10_12 + PIXEL11_0 + } + else + { + PIXEL10_61 + PIXEL11_90 + } + break; + } + case 236: + case 232: + { + PIXEL00_21 + PIXEL01_20 + if (Diff(w[8], w[4])) + { + PIXEL10_0 + PIXEL11_11 + } + else + { + PIXEL10_90 + PIXEL11_60 + } + break; + } + case 109: + case 105: + { + if (Diff(w[8], w[4])) + { + PIXEL00_12 + PIXEL10_0 + } + else + { + PIXEL00_61 + PIXEL10_90 + } + PIXEL01_20 + PIXEL11_22 + break; + } + case 171: + case 43: + { + if (Diff(w[4], w[2])) + { + PIXEL00_0 + PIXEL10_11 + } + else + { + PIXEL00_90 + PIXEL10_60 + } + PIXEL01_21 + PIXEL11_20 + break; + } + case 143: + case 15: + { + if (Diff(w[4], w[2])) + { + PIXEL00_0 + PIXEL01_12 + } + else + { + PIXEL00_90 + PIXEL01_61 + } + PIXEL10_22 + PIXEL11_20 + break; + } + case 124: + { + PIXEL00_21 + PIXEL01_11 + if (Diff(w[8], w[4])) + { + PIXEL10_0 + } + else + { + PIXEL10_20 + } + PIXEL11_10 + break; + } + case 203: + { + if (Diff(w[4], w[2])) + { + PIXEL00_0 + } + else + { + PIXEL00_20 + } + PIXEL01_21 + PIXEL10_10 + PIXEL11_11 + break; + } + case 62: + { + PIXEL00_10 + if (Diff(w[2], w[6])) + { + PIXEL01_0 + } + else + { + PIXEL01_20 + } + PIXEL10_11 + PIXEL11_21 + break; + } + case 211: + { + PIXEL00_11 + PIXEL01_10 + PIXEL10_21 + if (Diff(w[6], w[8])) + { + PIXEL11_0 + } + else + { + PIXEL11_20 + } + break; + } + case 118: + { + PIXEL00_22 + if (Diff(w[2], w[6])) + { + PIXEL01_0 + } + else + { + PIXEL01_20 + } + PIXEL10_12 + PIXEL11_10 + break; + } + case 217: + { + PIXEL00_12 + PIXEL01_22 + PIXEL10_10 + if (Diff(w[6], w[8])) + { + PIXEL11_0 + } + else + { + PIXEL11_20 + } + break; + } + case 110: + { + PIXEL00_10 + PIXEL01_12 + if (Diff(w[8], w[4])) + { + PIXEL10_0 + } + else + { + PIXEL10_20 + } + PIXEL11_22 + break; + } + case 155: + { + if (Diff(w[4], w[2])) + { + PIXEL00_0 + } + else + { + PIXEL00_20 + } + PIXEL01_10 + PIXEL10_22 + PIXEL11_12 + break; + } + case 188: + { + PIXEL00_21 + PIXEL01_11 + PIXEL10_11 + PIXEL11_12 + break; + } + case 185: + { + PIXEL00_12 + PIXEL01_22 + PIXEL10_11 + PIXEL11_12 + break; + } + case 61: + { + PIXEL00_12 + PIXEL01_11 + PIXEL10_11 + PIXEL11_21 + break; + } + case 157: + { + PIXEL00_12 + PIXEL01_11 + PIXEL10_22 + PIXEL11_12 + break; + } + case 103: + { + PIXEL00_11 + PIXEL01_12 + PIXEL10_12 + PIXEL11_22 + break; + } + case 227: + { + PIXEL00_11 + PIXEL01_21 + PIXEL10_12 + PIXEL11_11 + break; + } + case 230: + { + PIXEL00_22 + PIXEL01_12 + PIXEL10_12 + PIXEL11_11 + break; + } + case 199: + { + PIXEL00_11 + PIXEL01_12 + PIXEL10_21 + PIXEL11_11 + break; + } + case 220: + { + PIXEL00_21 + PIXEL01_11 + if (Diff(w[8], w[4])) + { + PIXEL10_10 + } + else + { + PIXEL10_70 + } + if (Diff(w[6], w[8])) + { + PIXEL11_0 + } + else + { + PIXEL11_20 + } + break; + } + case 158: + { + if (Diff(w[4], w[2])) + { + PIXEL00_10 + } + else + { + PIXEL00_70 + } + if (Diff(w[2], w[6])) + { + PIXEL01_0 + } + else + { + PIXEL01_20 + } + PIXEL10_22 + PIXEL11_12 + break; + } + case 234: + { + if (Diff(w[4], w[2])) + { + PIXEL00_10 + } + else + { + PIXEL00_70 + } + PIXEL01_21 + if (Diff(w[8], w[4])) + { + PIXEL10_0 + } + else + { + PIXEL10_20 + } + PIXEL11_11 + break; + } + case 242: + { + PIXEL00_22 + if (Diff(w[2], w[6])) + { + PIXEL01_10 + } + else + { + PIXEL01_70 + } + PIXEL10_12 + if (Diff(w[6], w[8])) + { + PIXEL11_0 + } + else + { + PIXEL11_20 + } + break; + } + case 59: + { + if (Diff(w[4], w[2])) + { + PIXEL00_0 + } + else + { + PIXEL00_20 + } + if (Diff(w[2], w[6])) + { + PIXEL01_10 + } + else + { + PIXEL01_70 + } + PIXEL10_11 + PIXEL11_21 + break; + } + case 121: + { + PIXEL00_12 + PIXEL01_22 + if (Diff(w[8], w[4])) + { + PIXEL10_0 + } + else + { + PIXEL10_20 + } + if (Diff(w[6], w[8])) + { + PIXEL11_10 + } + else + { + PIXEL11_70 + } + break; + } + case 87: + { + PIXEL00_11 + if (Diff(w[2], w[6])) + { + PIXEL01_0 + } + else + { + PIXEL01_20 + } + PIXEL10_21 + if (Diff(w[6], w[8])) + { + PIXEL11_10 + } + else + { + PIXEL11_70 + } + break; + } + case 79: + { + if (Diff(w[4], w[2])) + { + PIXEL00_0 + } + else + { + PIXEL00_20 + } + PIXEL01_12 + if (Diff(w[8], w[4])) + { + PIXEL10_10 + } + else + { + PIXEL10_70 + } + PIXEL11_22 + break; + } + case 122: + { + if (Diff(w[4], w[2])) + { + PIXEL00_10 + } + else + { + PIXEL00_70 + } + if (Diff(w[2], w[6])) + { + PIXEL01_10 + } + else + { + PIXEL01_70 + } + if (Diff(w[8], w[4])) + { + PIXEL10_0 + } + else + { + PIXEL10_20 + } + if (Diff(w[6], w[8])) + { + PIXEL11_10 + } + else + { + PIXEL11_70 + } + break; + } + case 94: + { + if (Diff(w[4], w[2])) + { + PIXEL00_10 + } + else + { + PIXEL00_70 + } + if (Diff(w[2], w[6])) + { + PIXEL01_0 + } + else + { + PIXEL01_20 + } + if (Diff(w[8], w[4])) + { + PIXEL10_10 + } + else + { + PIXEL10_70 + } + if (Diff(w[6], w[8])) + { + PIXEL11_10 + } + else + { + PIXEL11_70 + } + break; + } + case 218: + { + if (Diff(w[4], w[2])) + { + PIXEL00_10 + } + else + { + PIXEL00_70 + } + if (Diff(w[2], w[6])) + { + PIXEL01_10 + } + else + { + PIXEL01_70 + } + if (Diff(w[8], w[4])) + { + PIXEL10_10 + } + else + { + PIXEL10_70 + } + if (Diff(w[6], w[8])) + { + PIXEL11_0 + } + else + { + PIXEL11_20 + } + break; + } + case 91: + { + if (Diff(w[4], w[2])) + { + PIXEL00_0 + } + else + { + PIXEL00_20 + } + if (Diff(w[2], w[6])) + { + PIXEL01_10 + } + else + { + PIXEL01_70 + } + if (Diff(w[8], w[4])) + { + PIXEL10_10 + } + else + { + PIXEL10_70 + } + if (Diff(w[6], w[8])) + { + PIXEL11_10 + } + else + { + PIXEL11_70 + } + break; + } + case 229: + { + PIXEL00_20 + PIXEL01_20 + PIXEL10_12 + PIXEL11_11 + break; + } + case 167: + { + PIXEL00_11 + PIXEL01_12 + PIXEL10_20 + PIXEL11_20 + break; + } + case 173: + { + PIXEL00_12 + PIXEL01_20 + PIXEL10_11 + PIXEL11_20 + break; + } + case 181: + { + PIXEL00_20 + PIXEL01_11 + PIXEL10_20 + PIXEL11_12 + break; + } + case 186: + { + if (Diff(w[4], w[2])) + { + PIXEL00_10 + } + else + { + PIXEL00_70 + } + if (Diff(w[2], w[6])) + { + PIXEL01_10 + } + else + { + PIXEL01_70 + } + PIXEL10_11 + PIXEL11_12 + break; + } + case 115: + { + PIXEL00_11 + if (Diff(w[2], w[6])) + { + PIXEL01_10 + } + else + { + PIXEL01_70 + } + PIXEL10_12 + if (Diff(w[6], w[8])) + { + PIXEL11_10 + } + else + { + PIXEL11_70 + } + break; + } + case 93: + { + PIXEL00_12 + PIXEL01_11 + if (Diff(w[8], w[4])) + { + PIXEL10_10 + } + else + { + PIXEL10_70 + } + if (Diff(w[6], w[8])) + { + PIXEL11_10 + } + else + { + PIXEL11_70 + } + break; + } + case 206: + { + if (Diff(w[4], w[2])) + { + PIXEL00_10 + } + else + { + PIXEL00_70 + } + PIXEL01_12 + if (Diff(w[8], w[4])) + { + PIXEL10_10 + } + else + { + PIXEL10_70 + } + PIXEL11_11 + break; + } + case 205: + case 201: + { + PIXEL00_12 + PIXEL01_20 + if (Diff(w[8], w[4])) + { + PIXEL10_10 + } + else + { + PIXEL10_70 + } + PIXEL11_11 + break; + } + case 174: + case 46: + { + if (Diff(w[4], w[2])) + { + PIXEL00_10 + } + else + { + PIXEL00_70 + } + PIXEL01_12 + PIXEL10_11 + PIXEL11_20 + break; + } + case 179: + case 147: + { + PIXEL00_11 + if (Diff(w[2], w[6])) + { + PIXEL01_10 + } + else + { + PIXEL01_70 + } + PIXEL10_20 + PIXEL11_12 + break; + } + case 117: + case 116: + { + PIXEL00_20 + PIXEL01_11 + PIXEL10_12 + if (Diff(w[6], w[8])) + { + PIXEL11_10 + } + else + { + PIXEL11_70 + } + break; + } + case 189: + { + PIXEL00_12 + PIXEL01_11 + PIXEL10_11 + PIXEL11_12 + break; + } + case 231: + { + PIXEL00_11 + PIXEL01_12 + PIXEL10_12 + PIXEL11_11 + break; + } + case 126: + { + PIXEL00_10 + if (Diff(w[2], w[6])) + { + PIXEL01_0 + } + else + { + PIXEL01_20 + } + if (Diff(w[8], w[4])) + { + PIXEL10_0 + } + else + { + PIXEL10_20 + } + PIXEL11_10 + break; + } + case 219: + { + if (Diff(w[4], w[2])) + { + PIXEL00_0 + } + else + { + PIXEL00_20 + } + PIXEL01_10 + PIXEL10_10 + if (Diff(w[6], w[8])) + { + PIXEL11_0 + } + else + { + PIXEL11_20 + } + break; + } + case 125: + { + if (Diff(w[8], w[4])) + { + PIXEL00_12 + PIXEL10_0 + } + else + { + PIXEL00_61 + PIXEL10_90 + } + PIXEL01_11 + PIXEL11_10 + break; + } + case 221: + { + PIXEL00_12 + if (Diff(w[6], w[8])) + { + PIXEL01_11 + PIXEL11_0 + } + else + { + PIXEL01_60 + PIXEL11_90 + } + PIXEL10_10 + break; + } + case 207: + { + if (Diff(w[4], w[2])) + { + PIXEL00_0 + PIXEL01_12 + } + else + { + PIXEL00_90 + PIXEL01_61 + } + PIXEL10_10 + PIXEL11_11 + break; + } + case 238: + { + PIXEL00_10 + PIXEL01_12 + if (Diff(w[8], w[4])) + { + PIXEL10_0 + PIXEL11_11 + } + else + { + PIXEL10_90 + PIXEL11_60 + } + break; + } + case 190: + { + PIXEL00_10 + if (Diff(w[2], w[6])) + { + PIXEL01_0 + PIXEL11_12 + } + else + { + PIXEL01_90 + PIXEL11_61 + } + PIXEL10_11 + break; + } + case 187: + { + if (Diff(w[4], w[2])) + { + PIXEL00_0 + PIXEL10_11 + } + else + { + PIXEL00_90 + PIXEL10_60 + } + PIXEL01_10 + PIXEL11_12 + break; + } + case 243: + { + PIXEL00_11 + PIXEL01_10 + if (Diff(w[6], w[8])) + { + PIXEL10_12 + PIXEL11_0 + } + else + { + PIXEL10_61 + PIXEL11_90 + } + break; + } + case 119: + { + if (Diff(w[2], w[6])) + { + PIXEL00_11 + PIXEL01_0 + } + else + { + PIXEL00_60 + PIXEL01_90 + } + PIXEL10_12 + PIXEL11_10 + break; + } + case 237: + case 233: + { + PIXEL00_12 + PIXEL01_20 + if (Diff(w[8], w[4])) + { + PIXEL10_0 + } + else + { + PIXEL10_100 + } + PIXEL11_11 + break; + } + case 175: + case 47: + { + if (Diff(w[4], w[2])) + { + PIXEL00_0 + } + else + { + PIXEL00_100 + } + PIXEL01_12 + PIXEL10_11 + PIXEL11_20 + break; + } + case 183: + case 151: + { + PIXEL00_11 + if (Diff(w[2], w[6])) + { + PIXEL01_0 + } + else + { + PIXEL01_100 + } + PIXEL10_20 + PIXEL11_12 + break; + } + case 245: + case 244: + { + PIXEL00_20 + PIXEL01_11 + PIXEL10_12 + if (Diff(w[6], w[8])) + { + PIXEL11_0 + } + else + { + PIXEL11_100 + } + break; + } + case 250: + { + PIXEL00_10 + PIXEL01_10 + if (Diff(w[8], w[4])) + { + PIXEL10_0 + } + else + { + PIXEL10_20 + } + if (Diff(w[6], w[8])) + { + PIXEL11_0 + } + else + { + PIXEL11_20 + } + break; + } + case 123: + { + if (Diff(w[4], w[2])) + { + PIXEL00_0 + } + else + { + PIXEL00_20 + } + PIXEL01_10 + if (Diff(w[8], w[4])) + { + PIXEL10_0 + } + else + { + PIXEL10_20 + } + PIXEL11_10 + break; + } + case 95: + { + if (Diff(w[4], w[2])) + { + PIXEL00_0 + } + else + { + PIXEL00_20 + } + if (Diff(w[2], w[6])) + { + PIXEL01_0 + } + else + { + PIXEL01_20 + } + PIXEL10_10 + PIXEL11_10 + break; + } + case 222: + { + PIXEL00_10 + if (Diff(w[2], w[6])) + { + PIXEL01_0 + } + else + { + PIXEL01_20 + } + PIXEL10_10 + if (Diff(w[6], w[8])) + { + PIXEL11_0 + } + else + { + PIXEL11_20 + } + break; + } + case 252: + { + PIXEL00_21 + PIXEL01_11 + if (Diff(w[8], w[4])) + { + PIXEL10_0 + } + else + { + PIXEL10_20 + } + if (Diff(w[6], w[8])) + { + PIXEL11_0 + } + else + { + PIXEL11_100 + } + break; + } + case 249: + { + PIXEL00_12 + PIXEL01_22 + if (Diff(w[8], w[4])) + { + PIXEL10_0 + } + else + { + PIXEL10_100 + } + if (Diff(w[6], w[8])) + { + PIXEL11_0 + } + else + { + PIXEL11_20 + } + break; + } + case 235: + { + if (Diff(w[4], w[2])) + { + PIXEL00_0 + } + else + { + PIXEL00_20 + } + PIXEL01_21 + if (Diff(w[8], w[4])) + { + PIXEL10_0 + } + else + { + PIXEL10_100 + } + PIXEL11_11 + break; + } + case 111: + { + if (Diff(w[4], w[2])) + { + PIXEL00_0 + } + else + { + PIXEL00_100 + } + PIXEL01_12 + if (Diff(w[8], w[4])) + { + PIXEL10_0 + } + else + { + PIXEL10_20 + } + PIXEL11_22 + break; + } + case 63: + { + if (Diff(w[4], w[2])) + { + PIXEL00_0 + } + else + { + PIXEL00_100 + } + if (Diff(w[2], w[6])) + { + PIXEL01_0 + } + else + { + PIXEL01_20 + } + PIXEL10_11 + PIXEL11_21 + break; + } + case 159: + { + if (Diff(w[4], w[2])) + { + PIXEL00_0 + } + else + { + PIXEL00_20 + } + if (Diff(w[2], w[6])) + { + PIXEL01_0 + } + else + { + PIXEL01_100 + } + PIXEL10_22 + PIXEL11_12 + break; + } + case 215: + { + PIXEL00_11 + if (Diff(w[2], w[6])) + { + PIXEL01_0 + } + else + { + PIXEL01_100 + } + PIXEL10_21 + if (Diff(w[6], w[8])) + { + PIXEL11_0 + } + else + { + PIXEL11_20 + } + break; + } + case 246: + { + PIXEL00_22 + if (Diff(w[2], w[6])) + { + PIXEL01_0 + } + else + { + PIXEL01_20 + } + PIXEL10_12 + if (Diff(w[6], w[8])) + { + PIXEL11_0 + } + else + { + PIXEL11_100 + } + break; + } + case 254: + { + PIXEL00_10 + if (Diff(w[2], w[6])) + { + PIXEL01_0 + } + else + { + PIXEL01_20 + } + if (Diff(w[8], w[4])) + { + PIXEL10_0 + } + else + { + PIXEL10_20 + } + if (Diff(w[6], w[8])) + { + PIXEL11_0 + } + else + { + PIXEL11_100 + } + break; + } + case 253: + { + PIXEL00_12 + PIXEL01_11 + if (Diff(w[8], w[4])) + { + PIXEL10_0 + } + else + { + PIXEL10_100 + } + if (Diff(w[6], w[8])) + { + PIXEL11_0 + } + else + { + PIXEL11_100 + } + break; + } + case 251: + { + if (Diff(w[4], w[2])) + { + PIXEL00_0 + } + else + { + PIXEL00_20 + } + PIXEL01_10 + if (Diff(w[8], w[4])) + { + PIXEL10_0 + } + else + { + PIXEL10_100 + } + if (Diff(w[6], w[8])) + { + PIXEL11_0 + } + else + { + PIXEL11_20 + } + break; + } + case 239: + { + if (Diff(w[4], w[2])) + { + PIXEL00_0 + } + else + { + PIXEL00_100 + } + PIXEL01_12 + if (Diff(w[8], w[4])) + { + PIXEL10_0 + } + else + { + PIXEL10_100 + } + PIXEL11_11 + break; + } + case 127: + { + if (Diff(w[4], w[2])) + { + PIXEL00_0 + } + else + { + PIXEL00_100 + } + if (Diff(w[2], w[6])) + { + PIXEL01_0 + } + else + { + PIXEL01_20 + } + if (Diff(w[8], w[4])) + { + PIXEL10_0 + } + else + { + PIXEL10_20 + } + PIXEL11_10 + break; + } + case 191: + { + if (Diff(w[4], w[2])) + { + PIXEL00_0 + } + else + { + PIXEL00_100 + } + if (Diff(w[2], w[6])) + { + PIXEL01_0 + } + else + { + PIXEL01_100 + } + PIXEL10_11 + PIXEL11_12 + break; + } + case 223: + { + if (Diff(w[4], w[2])) + { + PIXEL00_0 + } + else + { + PIXEL00_20 + } + if (Diff(w[2], w[6])) + { + PIXEL01_0 + } + else + { + PIXEL01_100 + } + PIXEL10_10 + if (Diff(w[6], w[8])) + { + PIXEL11_0 + } + else + { + PIXEL11_20 + } + break; + } + case 247: + { + PIXEL00_11 + if (Diff(w[2], w[6])) + { + PIXEL01_0 + } + else + { + PIXEL01_100 + } + PIXEL10_12 + if (Diff(w[6], w[8])) + { + PIXEL11_0 + } + else + { + PIXEL11_100 + } + break; + } + case 255: + { + if (Diff(w[4], w[2])) + { + PIXEL00_0 + } + else + { + PIXEL00_100 + } + if (Diff(w[2], w[6])) + { + PIXEL01_0 + } + else + { + PIXEL01_100 + } + if (Diff(w[8], w[4])) + { + PIXEL10_0 + } + else + { + PIXEL10_100 + } + if (Diff(w[6], w[8])) + { + PIXEL11_0 + } + else + { + PIXEL11_100 + } + break; + } + } + pIn+=2; + pOut+=8; + } + pOut+=BpL; + } +} + +void InitHQ2X(void) +{ + int i, j, k, r, g, b, Y, u, v; + + for (i=0; i<65536; i++) + LUT16to32[i] = ((i & 0xF800) << 8) + ((i & 0x07E0) << 5) + ((i & 0x001F) << 3); + + for (i=0; i<32; i++) + for (j=0; j<64; j++) + for (k=0; k<32; k++) + { + r = i << 3; + g = j << 2; + b = k << 3; + Y = (r + g + b) >> 2; + u = 128 + ((r - b) >> 2); + v = 128 + ((-r + 2*g -b)>>3); + RGBtoYUV[ (i << 11) + (j << 5) + k ] = (Y<<16) + (u<<8) + v; + } +} + diff --git a/engines/vileVN/external/hq2x/hq2x.h b/engines/vileVN/external/hq2x/hq2x.h new file mode 100644 index 0000000000..ab08b374d4 --- /dev/null +++ b/engines/vileVN/external/hq2x/hq2x.h @@ -0,0 +1,9 @@ +#ifndef _HQ2X_H_ +#define _HQ2X_H_ + +extern void InitHQ2X(void); +extern void hq2x_32(unsigned char *In, + unsigned char *Out,int Xres,int Yres,int BpL); + +#endif + diff --git a/engines/vileVN/external/hq3x/hq3x.cpp b/engines/vileVN/external/hq3x/hq3x.cpp new file mode 100644 index 0000000000..942559350e --- /dev/null +++ b/engines/vileVN/external/hq3x/hq3x.cpp @@ -0,0 +1,3849 @@ +//hq3x filter demo program +//---------------------------------------------------------- +//Copyright (C) 2003 MaxSt ( maxst@hiend3d.com ) + +//This program is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This program is distributed in the hope that it will be useful, +//but WITHOUT ANY WARRANTY; without even the implied warranty of +//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +//Lesser General Public License for more details. +// +//You should have received a copy of the GNU Lesser General Public +//License along with this program; if not, write to the Free Software +//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +#include +#include +#include + +static int LUT16to32[65536]; +static int RGBtoYUV[65536]; +static int YUV1, YUV2; +const int Ymask = 0x00FF0000; +const int Umask = 0x0000FF00; +const int Vmask = 0x000000FF; +const int trY = 0x00300000; +const int trU = 0x00000700; +const int trV = 0x00000006; + +inline void Interp1(unsigned char * pc, int c1, int c2) +{ + *((int*)pc) = (c1*3+c2) >> 2; +} + +inline void Interp2(unsigned char * pc, int c1, int c2, int c3) +{ + *((int*)pc) = (c1*2+c2+c3) >> 2; +} + +inline void Interp3(unsigned char * pc, int c1, int c2) +{ + //*((int*)pc) = (c1*7+c2)/8; + + *((int*)pc) = ((((c1 & 0x00FF00)*7 + (c2 & 0x00FF00) ) & 0x0007F800) + + (((c1 & 0xFF00FF)*7 + (c2 & 0xFF00FF) ) & 0x07F807F8)) >> 3; +} + +inline void Interp4(unsigned char * pc, int c1, int c2, int c3) +{ + //*((int*)pc) = (c1*2+(c2+c3)*7)/16; + + *((int*)pc) = ((((c1 & 0x00FF00)*2 + ((c2 & 0x00FF00) + (c3 & 0x00FF00))*7 ) & 0x000FF000) + + (((c1 & 0xFF00FF)*2 + ((c2 & 0xFF00FF) + (c3 & 0xFF00FF))*7 ) & 0x0FF00FF0)) >> 4; +} + +inline void Interp5(unsigned char * pc, int c1, int c2) +{ + *((int*)pc) = (c1+c2) >> 1; +} + +#define PIXEL00_1M Interp1(pOut, c[5], c[1]); +#define PIXEL00_1U Interp1(pOut, c[5], c[2]); +#define PIXEL00_1L Interp1(pOut, c[5], c[4]); +#define PIXEL00_2 Interp2(pOut, c[5], c[4], c[2]); +#define PIXEL00_4 Interp4(pOut, c[5], c[4], c[2]); +#define PIXEL00_5 Interp5(pOut, c[4], c[2]); +#define PIXEL00_C *((int*)(pOut)) = c[5]; + +#define PIXEL01_1 Interp1(pOut+4, c[5], c[2]); +#define PIXEL01_3 Interp3(pOut+4, c[5], c[2]); +#define PIXEL01_6 Interp1(pOut+4, c[2], c[5]); +#define PIXEL01_C *((int*)(pOut+4)) = c[5]; + +#define PIXEL02_1M Interp1(pOut+8, c[5], c[3]); +#define PIXEL02_1U Interp1(pOut+8, c[5], c[2]); +#define PIXEL02_1R Interp1(pOut+8, c[5], c[6]); +#define PIXEL02_2 Interp2(pOut+8, c[5], c[2], c[6]); +#define PIXEL02_4 Interp4(pOut+8, c[5], c[2], c[6]); +#define PIXEL02_5 Interp5(pOut+8, c[2], c[6]); +#define PIXEL02_C *((int*)(pOut+8)) = c[5]; + +#define PIXEL10_1 Interp1(pOut+BpL, c[5], c[4]); +#define PIXEL10_3 Interp3(pOut+BpL, c[5], c[4]); +#define PIXEL10_6 Interp1(pOut+BpL, c[4], c[5]); +#define PIXEL10_C *((int*)(pOut+BpL)) = c[5]; + +#define PIXEL11 *((int*)(pOut+BpL+4)) = c[5]; + +#define PIXEL12_1 Interp1(pOut+BpL+8, c[5], c[6]); +#define PIXEL12_3 Interp3(pOut+BpL+8, c[5], c[6]); +#define PIXEL12_6 Interp1(pOut+BpL+8, c[6], c[5]); +#define PIXEL12_C *((int*)(pOut+BpL+8)) = c[5]; + +#define PIXEL20_1M Interp1(pOut+BpL+BpL, c[5], c[7]); +#define PIXEL20_1D Interp1(pOut+BpL+BpL, c[5], c[8]); +#define PIXEL20_1L Interp1(pOut+BpL+BpL, c[5], c[4]); +#define PIXEL20_2 Interp2(pOut+BpL+BpL, c[5], c[8], c[4]); +#define PIXEL20_4 Interp4(pOut+BpL+BpL, c[5], c[8], c[4]); +#define PIXEL20_5 Interp5(pOut+BpL+BpL, c[8], c[4]); +#define PIXEL20_C *((int*)(pOut+BpL+BpL)) = c[5]; + +#define PIXEL21_1 Interp1(pOut+BpL+BpL+4, c[5], c[8]); +#define PIXEL21_3 Interp3(pOut+BpL+BpL+4, c[5], c[8]); +#define PIXEL21_6 Interp1(pOut+BpL+BpL+4, c[8], c[5]); +#define PIXEL21_C *((int*)(pOut+BpL+BpL+4)) = c[5]; + +#define PIXEL22_1M Interp1(pOut+BpL+BpL+8, c[5], c[9]); +#define PIXEL22_1D Interp1(pOut+BpL+BpL+8, c[5], c[8]); +#define PIXEL22_1R Interp1(pOut+BpL+BpL+8, c[5], c[6]); +#define PIXEL22_2 Interp2(pOut+BpL+BpL+8, c[5], c[6], c[8]); +#define PIXEL22_4 Interp4(pOut+BpL+BpL+8, c[5], c[6], c[8]); +#define PIXEL22_5 Interp5(pOut+BpL+BpL+8, c[6], c[8]); +#define PIXEL22_C *((int*)(pOut+BpL+BpL+8)) = c[5]; + +inline bool Diff(unsigned int w1, unsigned int w2) +{ + YUV1 = RGBtoYUV[w1]; + YUV2 = RGBtoYUV[w2]; + return ( ( abs((YUV1 & Ymask) - (YUV2 & Ymask)) > trY ) || + ( abs((YUV1 & Umask) - (YUV2 & Umask)) > trU ) || + ( abs((YUV1 & Vmask) - (YUV2 & Vmask)) > trV ) ); +} + +void hq3x_32( unsigned char * pIn, unsigned char * pOut, int Xres, int Yres, int BpL ) +{ + int i, j, k; + int prevline, nextline; + int w[10]; + int c[10]; + + // +----+----+----+ + // | | | | + // | w1 | w2 | w3 | + // +----+----+----+ + // | | | | + // | w4 | w5 | w6 | + // +----+----+----+ + // | | | | + // | w7 | w8 | w9 | + // +----+----+----+ + + for (j=0; j0) prevline = -Xres*2; else prevline = 0; + if (j0) + { + w[1] = *((unsigned short*)(pIn + prevline - 2)); + w[4] = *((unsigned short*)(pIn - 2)); + w[7] = *((unsigned short*)(pIn + nextline - 2)); + } + else + { + w[1] = w[2]; + w[4] = w[5]; + w[7] = w[8]; + } + + if (i trY ) || + ( abs((YUV1 & Umask) - (YUV2 & Umask)) > trU ) || + ( abs((YUV1 & Vmask) - (YUV2 & Vmask)) > trV ) ) + pattern |= flag; + } + flag <<= 1; + } + + for (k=1; k<=9; k++) + c[k] = LUT16to32[w[k]]; + + switch (pattern) + { + case 0: + case 1: + case 4: + case 32: + case 128: + case 5: + case 132: + case 160: + case 33: + case 129: + case 36: + case 133: + case 164: + case 161: + case 37: + case 165: + { + PIXEL00_2 + PIXEL01_1 + PIXEL02_2 + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_2 + PIXEL21_1 + PIXEL22_2 + break; + } + case 2: + case 34: + case 130: + case 162: + { + PIXEL00_1M + PIXEL01_C + PIXEL02_1M + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_2 + PIXEL21_1 + PIXEL22_2 + break; + } + case 16: + case 17: + case 48: + case 49: + { + PIXEL00_2 + PIXEL01_1 + PIXEL02_1M + PIXEL10_1 + PIXEL11 + PIXEL12_C + PIXEL20_2 + PIXEL21_1 + PIXEL22_1M + break; + } + case 64: + case 65: + case 68: + case 69: + { + PIXEL00_2 + PIXEL01_1 + PIXEL02_2 + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_C + PIXEL22_1M + break; + } + case 8: + case 12: + case 136: + case 140: + { + PIXEL00_1M + PIXEL01_1 + PIXEL02_2 + PIXEL10_C + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_1 + PIXEL22_2 + break; + } + case 3: + case 35: + case 131: + case 163: + { + PIXEL00_1L + PIXEL01_C + PIXEL02_1M + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_2 + PIXEL21_1 + PIXEL22_2 + break; + } + case 6: + case 38: + case 134: + case 166: + { + PIXEL00_1M + PIXEL01_C + PIXEL02_1R + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_2 + PIXEL21_1 + PIXEL22_2 + break; + } + case 20: + case 21: + case 52: + case 53: + { + PIXEL00_2 + PIXEL01_1 + PIXEL02_1U + PIXEL10_1 + PIXEL11 + PIXEL12_C + PIXEL20_2 + PIXEL21_1 + PIXEL22_1M + break; + } + case 144: + case 145: + case 176: + case 177: + { + PIXEL00_2 + PIXEL01_1 + PIXEL02_1M + PIXEL10_1 + PIXEL11 + PIXEL12_C + PIXEL20_2 + PIXEL21_1 + PIXEL22_1D + break; + } + case 192: + case 193: + case 196: + case 197: + { + PIXEL00_2 + PIXEL01_1 + PIXEL02_2 + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_C + PIXEL22_1R + break; + } + case 96: + case 97: + case 100: + case 101: + { + PIXEL00_2 + PIXEL01_1 + PIXEL02_2 + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1L + PIXEL21_C + PIXEL22_1M + break; + } + case 40: + case 44: + case 168: + case 172: + { + PIXEL00_1M + PIXEL01_1 + PIXEL02_2 + PIXEL10_C + PIXEL11 + PIXEL12_1 + PIXEL20_1D + PIXEL21_1 + PIXEL22_2 + break; + } + case 9: + case 13: + case 137: + case 141: + { + PIXEL00_1U + PIXEL01_1 + PIXEL02_2 + PIXEL10_C + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_1 + PIXEL22_2 + break; + } + case 18: + case 50: + { + PIXEL00_1M + if (Diff(w[2], w[6])) + { + PIXEL01_C + PIXEL02_1M + PIXEL12_C + } + else + { + PIXEL01_3 + PIXEL02_4 + PIXEL12_3 + } + PIXEL10_1 + PIXEL11 + PIXEL20_2 + PIXEL21_1 + PIXEL22_1M + break; + } + case 80: + case 81: + { + PIXEL00_2 + PIXEL01_1 + PIXEL02_1M + PIXEL10_1 + PIXEL11 + PIXEL20_1M + if (Diff(w[6], w[8])) + { + PIXEL12_C + PIXEL21_C + PIXEL22_1M + } + else + { + PIXEL12_3 + PIXEL21_3 + PIXEL22_4 + } + break; + } + case 72: + case 76: + { + PIXEL00_1M + PIXEL01_1 + PIXEL02_2 + PIXEL11 + PIXEL12_1 + if (Diff(w[8], w[4])) + { + PIXEL10_C + PIXEL20_1M + PIXEL21_C + } + else + { + PIXEL10_3 + PIXEL20_4 + PIXEL21_3 + } + PIXEL22_1M + break; + } + case 10: + case 138: + { + if (Diff(w[4], w[2])) + { + PIXEL00_1M + PIXEL01_C + PIXEL10_C + } + else + { + PIXEL00_4 + PIXEL01_3 + PIXEL10_3 + } + PIXEL02_1M + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_1 + PIXEL22_2 + break; + } + case 66: + { + PIXEL00_1M + PIXEL01_C + PIXEL02_1M + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_C + PIXEL22_1M + break; + } + case 24: + { + PIXEL00_1M + PIXEL01_1 + PIXEL02_1M + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1M + PIXEL21_1 + PIXEL22_1M + break; + } + case 7: + case 39: + case 135: + { + PIXEL00_1L + PIXEL01_C + PIXEL02_1R + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_2 + PIXEL21_1 + PIXEL22_2 + break; + } + case 148: + case 149: + case 180: + { + PIXEL00_2 + PIXEL01_1 + PIXEL02_1U + PIXEL10_1 + PIXEL11 + PIXEL12_C + PIXEL20_2 + PIXEL21_1 + PIXEL22_1D + break; + } + case 224: + case 228: + case 225: + { + PIXEL00_2 + PIXEL01_1 + PIXEL02_2 + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1L + PIXEL21_C + PIXEL22_1R + break; + } + case 41: + case 169: + case 45: + { + PIXEL00_1U + PIXEL01_1 + PIXEL02_2 + PIXEL10_C + PIXEL11 + PIXEL12_1 + PIXEL20_1D + PIXEL21_1 + PIXEL22_2 + break; + } + case 22: + case 54: + { + PIXEL00_1M + if (Diff(w[2], w[6])) + { + PIXEL01_C + PIXEL02_C + PIXEL12_C + } + else + { + PIXEL01_3 + PIXEL02_4 + PIXEL12_3 + } + PIXEL10_1 + PIXEL11 + PIXEL20_2 + PIXEL21_1 + PIXEL22_1M + break; + } + case 208: + case 209: + { + PIXEL00_2 + PIXEL01_1 + PIXEL02_1M + PIXEL10_1 + PIXEL11 + PIXEL20_1M + if (Diff(w[6], w[8])) + { + PIXEL12_C + PIXEL21_C + PIXEL22_C + } + else + { + PIXEL12_3 + PIXEL21_3 + PIXEL22_4 + } + break; + } + case 104: + case 108: + { + PIXEL00_1M + PIXEL01_1 + PIXEL02_2 + PIXEL11 + PIXEL12_1 + if (Diff(w[8], w[4])) + { + PIXEL10_C + PIXEL20_C + PIXEL21_C + } + else + { + PIXEL10_3 + PIXEL20_4 + PIXEL21_3 + } + PIXEL22_1M + break; + } + case 11: + case 139: + { + if (Diff(w[4], w[2])) + { + PIXEL00_C + PIXEL01_C + PIXEL10_C + } + else + { + PIXEL00_4 + PIXEL01_3 + PIXEL10_3 + } + PIXEL02_1M + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_1 + PIXEL22_2 + break; + } + case 19: + case 51: + { + if (Diff(w[2], w[6])) + { + PIXEL00_1L + PIXEL01_C + PIXEL02_1M + PIXEL12_C + } + else + { + PIXEL00_2 + PIXEL01_6 + PIXEL02_5 + PIXEL12_1 + } + PIXEL10_1 + PIXEL11 + PIXEL20_2 + PIXEL21_1 + PIXEL22_1M + break; + } + case 146: + case 178: + { + if (Diff(w[2], w[6])) + { + PIXEL01_C + PIXEL02_1M + PIXEL12_C + PIXEL22_1D + } + else + { + PIXEL01_1 + PIXEL02_5 + PIXEL12_6 + PIXEL22_2 + } + PIXEL00_1M + PIXEL10_1 + PIXEL11 + PIXEL20_2 + PIXEL21_1 + break; + } + case 84: + case 85: + { + if (Diff(w[6], w[8])) + { + PIXEL02_1U + PIXEL12_C + PIXEL21_C + PIXEL22_1M + } + else + { + PIXEL02_2 + PIXEL12_6 + PIXEL21_1 + PIXEL22_5 + } + PIXEL00_2 + PIXEL01_1 + PIXEL10_1 + PIXEL11 + PIXEL20_1M + break; + } + case 112: + case 113: + { + if (Diff(w[6], w[8])) + { + PIXEL12_C + PIXEL20_1L + PIXEL21_C + PIXEL22_1M + } + else + { + PIXEL12_1 + PIXEL20_2 + PIXEL21_6 + PIXEL22_5 + } + PIXEL00_2 + PIXEL01_1 + PIXEL02_1M + PIXEL10_1 + PIXEL11 + break; + } + case 200: + case 204: + { + if (Diff(w[8], w[4])) + { + PIXEL10_C + PIXEL20_1M + PIXEL21_C + PIXEL22_1R + } + else + { + PIXEL10_1 + PIXEL20_5 + PIXEL21_6 + PIXEL22_2 + } + PIXEL00_1M + PIXEL01_1 + PIXEL02_2 + PIXEL11 + PIXEL12_1 + break; + } + case 73: + case 77: + { + if (Diff(w[8], w[4])) + { + PIXEL00_1U + PIXEL10_C + PIXEL20_1M + PIXEL21_C + } + else + { + PIXEL00_2 + PIXEL10_6 + PIXEL20_5 + PIXEL21_1 + } + PIXEL01_1 + PIXEL02_2 + PIXEL11 + PIXEL12_1 + PIXEL22_1M + break; + } + case 42: + case 170: + { + if (Diff(w[4], w[2])) + { + PIXEL00_1M + PIXEL01_C + PIXEL10_C + PIXEL20_1D + } + else + { + PIXEL00_5 + PIXEL01_1 + PIXEL10_6 + PIXEL20_2 + } + PIXEL02_1M + PIXEL11 + PIXEL12_1 + PIXEL21_1 + PIXEL22_2 + break; + } + case 14: + case 142: + { + if (Diff(w[4], w[2])) + { + PIXEL00_1M + PIXEL01_C + PIXEL02_1R + PIXEL10_C + } + else + { + PIXEL00_5 + PIXEL01_6 + PIXEL02_2 + PIXEL10_1 + } + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_1 + PIXEL22_2 + break; + } + case 67: + { + PIXEL00_1L + PIXEL01_C + PIXEL02_1M + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_C + PIXEL22_1M + break; + } + case 70: + { + PIXEL00_1M + PIXEL01_C + PIXEL02_1R + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_C + PIXEL22_1M + break; + } + case 28: + { + PIXEL00_1M + PIXEL01_1 + PIXEL02_1U + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1M + PIXEL21_1 + PIXEL22_1M + break; + } + case 152: + { + PIXEL00_1M + PIXEL01_1 + PIXEL02_1M + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1M + PIXEL21_1 + PIXEL22_1D + break; + } + case 194: + { + PIXEL00_1M + PIXEL01_C + PIXEL02_1M + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_C + PIXEL22_1R + break; + } + case 98: + { + PIXEL00_1M + PIXEL01_C + PIXEL02_1M + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1L + PIXEL21_C + PIXEL22_1M + break; + } + case 56: + { + PIXEL00_1M + PIXEL01_1 + PIXEL02_1M + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1D + PIXEL21_1 + PIXEL22_1M + break; + } + case 25: + { + PIXEL00_1U + PIXEL01_1 + PIXEL02_1M + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1M + PIXEL21_1 + PIXEL22_1M + break; + } + case 26: + case 31: + { + if (Diff(w[4], w[2])) + { + PIXEL00_C + PIXEL10_C + } + else + { + PIXEL00_4 + PIXEL10_3 + } + PIXEL01_C + if (Diff(w[2], w[6])) + { + PIXEL02_C + PIXEL12_C + } + else + { + PIXEL02_4 + PIXEL12_3 + } + PIXEL11 + PIXEL20_1M + PIXEL21_1 + PIXEL22_1M + break; + } + case 82: + case 214: + { + PIXEL00_1M + if (Diff(w[2], w[6])) + { + PIXEL01_C + PIXEL02_C + } + else + { + PIXEL01_3 + PIXEL02_4 + } + PIXEL10_1 + PIXEL11 + PIXEL12_C + PIXEL20_1M + if (Diff(w[6], w[8])) + { + PIXEL21_C + PIXEL22_C + } + else + { + PIXEL21_3 + PIXEL22_4 + } + break; + } + case 88: + case 248: + { + PIXEL00_1M + PIXEL01_1 + PIXEL02_1M + PIXEL11 + if (Diff(w[8], w[4])) + { + PIXEL10_C + PIXEL20_C + } + else + { + PIXEL10_3 + PIXEL20_4 + } + PIXEL21_C + if (Diff(w[6], w[8])) + { + PIXEL12_C + PIXEL22_C + } + else + { + PIXEL12_3 + PIXEL22_4 + } + break; + } + case 74: + case 107: + { + if (Diff(w[4], w[2])) + { + PIXEL00_C + PIXEL01_C + } + else + { + PIXEL00_4 + PIXEL01_3 + } + PIXEL02_1M + PIXEL10_C + PIXEL11 + PIXEL12_1 + if (Diff(w[8], w[4])) + { + PIXEL20_C + PIXEL21_C + } + else + { + PIXEL20_4 + PIXEL21_3 + } + PIXEL22_1M + break; + } + case 27: + { + if (Diff(w[4], w[2])) + { + PIXEL00_C + PIXEL01_C + PIXEL10_C + } + else + { + PIXEL00_4 + PIXEL01_3 + PIXEL10_3 + } + PIXEL02_1M + PIXEL11 + PIXEL12_C + PIXEL20_1M + PIXEL21_1 + PIXEL22_1M + break; + } + case 86: + { + PIXEL00_1M + if (Diff(w[2], w[6])) + { + PIXEL01_C + PIXEL02_C + PIXEL12_C + } + else + { + PIXEL01_3 + PIXEL02_4 + PIXEL12_3 + } + PIXEL10_1 + PIXEL11 + PIXEL20_1M + PIXEL21_C + PIXEL22_1M + break; + } + case 216: + { + PIXEL00_1M + PIXEL01_1 + PIXEL02_1M + PIXEL10_C + PIXEL11 + PIXEL20_1M + if (Diff(w[6], w[8])) + { + PIXEL12_C + PIXEL21_C + PIXEL22_C + } + else + { + PIXEL12_3 + PIXEL21_3 + PIXEL22_4 + } + break; + } + case 106: + { + PIXEL00_1M + PIXEL01_C + PIXEL02_1M + PIXEL11 + PIXEL12_1 + if (Diff(w[8], w[4])) + { + PIXEL10_C + PIXEL20_C + PIXEL21_C + } + else + { + PIXEL10_3 + PIXEL20_4 + PIXEL21_3 + } + PIXEL22_1M + break; + } + case 30: + { + PIXEL00_1M + if (Diff(w[2], w[6])) + { + PIXEL01_C + PIXEL02_C + PIXEL12_C + } + else + { + PIXEL01_3 + PIXEL02_4 + PIXEL12_3 + } + PIXEL10_C + PIXEL11 + PIXEL20_1M + PIXEL21_1 + PIXEL22_1M + break; + } + case 210: + { + PIXEL00_1M + PIXEL01_C + PIXEL02_1M + PIXEL10_1 + PIXEL11 + PIXEL20_1M + if (Diff(w[6], w[8])) + { + PIXEL12_C + PIXEL21_C + PIXEL22_C + } + else + { + PIXEL12_3 + PIXEL21_3 + PIXEL22_4 + } + break; + } + case 120: + { + PIXEL00_1M + PIXEL01_1 + PIXEL02_1M + PIXEL11 + PIXEL12_C + if (Diff(w[8], w[4])) + { + PIXEL10_C + PIXEL20_C + PIXEL21_C + } + else + { + PIXEL10_3 + PIXEL20_4 + PIXEL21_3 + } + PIXEL22_1M + break; + } + case 75: + { + if (Diff(w[4], w[2])) + { + PIXEL00_C + PIXEL01_C + PIXEL10_C + } + else + { + PIXEL00_4 + PIXEL01_3 + PIXEL10_3 + } + PIXEL02_1M + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_C + PIXEL22_1M + break; + } + case 29: + { + PIXEL00_1U + PIXEL01_1 + PIXEL02_1U + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1M + PIXEL21_1 + PIXEL22_1M + break; + } + case 198: + { + PIXEL00_1M + PIXEL01_C + PIXEL02_1R + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_C + PIXEL22_1R + break; + } + case 184: + { + PIXEL00_1M + PIXEL01_1 + PIXEL02_1M + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1D + PIXEL21_1 + PIXEL22_1D + break; + } + case 99: + { + PIXEL00_1L + PIXEL01_C + PIXEL02_1M + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1L + PIXEL21_C + PIXEL22_1M + break; + } + case 57: + { + PIXEL00_1U + PIXEL01_1 + PIXEL02_1M + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1D + PIXEL21_1 + PIXEL22_1M + break; + } + case 71: + { + PIXEL00_1L + PIXEL01_C + PIXEL02_1R + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_C + PIXEL22_1M + break; + } + case 156: + { + PIXEL00_1M + PIXEL01_1 + PIXEL02_1U + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1M + PIXEL21_1 + PIXEL22_1D + break; + } + case 226: + { + PIXEL00_1M + PIXEL01_C + PIXEL02_1M + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1L + PIXEL21_C + PIXEL22_1R + break; + } + case 60: + { + PIXEL00_1M + PIXEL01_1 + PIXEL02_1U + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1D + PIXEL21_1 + PIXEL22_1M + break; + } + case 195: + { + PIXEL00_1L + PIXEL01_C + PIXEL02_1M + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_C + PIXEL22_1R + break; + } + case 102: + { + PIXEL00_1M + PIXEL01_C + PIXEL02_1R + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1L + PIXEL21_C + PIXEL22_1M + break; + } + case 153: + { + PIXEL00_1U + PIXEL01_1 + PIXEL02_1M + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1M + PIXEL21_1 + PIXEL22_1D + break; + } + case 58: + { + if (Diff(w[4], w[2])) + { + PIXEL00_1M + } + else + { + PIXEL00_2 + } + PIXEL01_C + if (Diff(w[2], w[6])) + { + PIXEL02_1M + } + else + { + PIXEL02_2 + } + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1D + PIXEL21_1 + PIXEL22_1M + break; + } + case 83: + { + PIXEL00_1L + PIXEL01_C + if (Diff(w[2], w[6])) + { + PIXEL02_1M + } + else + { + PIXEL02_2 + } + PIXEL10_1 + PIXEL11 + PIXEL12_C + PIXEL20_1M + PIXEL21_C + if (Diff(w[6], w[8])) + { + PIXEL22_1M + } + else + { + PIXEL22_2 + } + break; + } + case 92: + { + PIXEL00_1M + PIXEL01_1 + PIXEL02_1U + PIXEL10_C + PIXEL11 + PIXEL12_C + if (Diff(w[8], w[4])) + { + PIXEL20_1M + } + else + { + PIXEL20_2 + } + PIXEL21_C + if (Diff(w[6], w[8])) + { + PIXEL22_1M + } + else + { + PIXEL22_2 + } + break; + } + case 202: + { + if (Diff(w[4], w[2])) + { + PIXEL00_1M + } + else + { + PIXEL00_2 + } + PIXEL01_C + PIXEL02_1M + PIXEL10_C + PIXEL11 + PIXEL12_1 + if (Diff(w[8], w[4])) + { + PIXEL20_1M + } + else + { + PIXEL20_2 + } + PIXEL21_C + PIXEL22_1R + break; + } + case 78: + { + if (Diff(w[4], w[2])) + { + PIXEL00_1M + } + else + { + PIXEL00_2 + } + PIXEL01_C + PIXEL02_1R + PIXEL10_C + PIXEL11 + PIXEL12_1 + if (Diff(w[8], w[4])) + { + PIXEL20_1M + } + else + { + PIXEL20_2 + } + PIXEL21_C + PIXEL22_1M + break; + } + case 154: + { + if (Diff(w[4], w[2])) + { + PIXEL00_1M + } + else + { + PIXEL00_2 + } + PIXEL01_C + if (Diff(w[2], w[6])) + { + PIXEL02_1M + } + else + { + PIXEL02_2 + } + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1M + PIXEL21_1 + PIXEL22_1D + break; + } + case 114: + { + PIXEL00_1M + PIXEL01_C + if (Diff(w[2], w[6])) + { + PIXEL02_1M + } + else + { + PIXEL02_2 + } + PIXEL10_1 + PIXEL11 + PIXEL12_C + PIXEL20_1L + PIXEL21_C + if (Diff(w[6], w[8])) + { + PIXEL22_1M + } + else + { + PIXEL22_2 + } + break; + } + case 89: + { + PIXEL00_1U + PIXEL01_1 + PIXEL02_1M + PIXEL10_C + PIXEL11 + PIXEL12_C + if (Diff(w[8], w[4])) + { + PIXEL20_1M + } + else + { + PIXEL20_2 + } + PIXEL21_C + if (Diff(w[6], w[8])) + { + PIXEL22_1M + } + else + { + PIXEL22_2 + } + break; + } + case 90: + { + if (Diff(w[4], w[2])) + { + PIXEL00_1M + } + else + { + PIXEL00_2 + } + PIXEL01_C + if (Diff(w[2], w[6])) + { + PIXEL02_1M + } + else + { + PIXEL02_2 + } + PIXEL10_C + PIXEL11 + PIXEL12_C + if (Diff(w[8], w[4])) + { + PIXEL20_1M + } + else + { + PIXEL20_2 + } + PIXEL21_C + if (Diff(w[6], w[8])) + { + PIXEL22_1M + } + else + { + PIXEL22_2 + } + break; + } + case 55: + case 23: + { + if (Diff(w[2], w[6])) + { + PIXEL00_1L + PIXEL01_C + PIXEL02_C + PIXEL12_C + } + else + { + PIXEL00_2 + PIXEL01_6 + PIXEL02_5 + PIXEL12_1 + } + PIXEL10_1 + PIXEL11 + PIXEL20_2 + PIXEL21_1 + PIXEL22_1M + break; + } + case 182: + case 150: + { + if (Diff(w[2], w[6])) + { + PIXEL01_C + PIXEL02_C + PIXEL12_C + PIXEL22_1D + } + else + { + PIXEL01_1 + PIXEL02_5 + PIXEL12_6 + PIXEL22_2 + } + PIXEL00_1M + PIXEL10_1 + PIXEL11 + PIXEL20_2 + PIXEL21_1 + break; + } + case 213: + case 212: + { + if (Diff(w[6], w[8])) + { + PIXEL02_1U + PIXEL12_C + PIXEL21_C + PIXEL22_C + } + else + { + PIXEL02_2 + PIXEL12_6 + PIXEL21_1 + PIXEL22_5 + } + PIXEL00_2 + PIXEL01_1 + PIXEL10_1 + PIXEL11 + PIXEL20_1M + break; + } + case 241: + case 240: + { + if (Diff(w[6], w[8])) + { + PIXEL12_C + PIXEL20_1L + PIXEL21_C + PIXEL22_C + } + else + { + PIXEL12_1 + PIXEL20_2 + PIXEL21_6 + PIXEL22_5 + } + PIXEL00_2 + PIXEL01_1 + PIXEL02_1M + PIXEL10_1 + PIXEL11 + break; + } + case 236: + case 232: + { + if (Diff(w[8], w[4])) + { + PIXEL10_C + PIXEL20_C + PIXEL21_C + PIXEL22_1R + } + else + { + PIXEL10_1 + PIXEL20_5 + PIXEL21_6 + PIXEL22_2 + } + PIXEL00_1M + PIXEL01_1 + PIXEL02_2 + PIXEL11 + PIXEL12_1 + break; + } + case 109: + case 105: + { + if (Diff(w[8], w[4])) + { + PIXEL00_1U + PIXEL10_C + PIXEL20_C + PIXEL21_C + } + else + { + PIXEL00_2 + PIXEL10_6 + PIXEL20_5 + PIXEL21_1 + } + PIXEL01_1 + PIXEL02_2 + PIXEL11 + PIXEL12_1 + PIXEL22_1M + break; + } + case 171: + case 43: + { + if (Diff(w[4], w[2])) + { + PIXEL00_C + PIXEL01_C + PIXEL10_C + PIXEL20_1D + } + else + { + PIXEL00_5 + PIXEL01_1 + PIXEL10_6 + PIXEL20_2 + } + PIXEL02_1M + PIXEL11 + PIXEL12_1 + PIXEL21_1 + PIXEL22_2 + break; + } + case 143: + case 15: + { + if (Diff(w[4], w[2])) + { + PIXEL00_C + PIXEL01_C + PIXEL02_1R + PIXEL10_C + } + else + { + PIXEL00_5 + PIXEL01_6 + PIXEL02_2 + PIXEL10_1 + } + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_1 + PIXEL22_2 + break; + } + case 124: + { + PIXEL00_1M + PIXEL01_1 + PIXEL02_1U + PIXEL11 + PIXEL12_C + if (Diff(w[8], w[4])) + { + PIXEL10_C + PIXEL20_C + PIXEL21_C + } + else + { + PIXEL10_3 + PIXEL20_4 + PIXEL21_3 + } + PIXEL22_1M + break; + } + case 203: + { + if (Diff(w[4], w[2])) + { + PIXEL00_C + PIXEL01_C + PIXEL10_C + } + else + { + PIXEL00_4 + PIXEL01_3 + PIXEL10_3 + } + PIXEL02_1M + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_C + PIXEL22_1R + break; + } + case 62: + { + PIXEL00_1M + if (Diff(w[2], w[6])) + { + PIXEL01_C + PIXEL02_C + PIXEL12_C + } + else + { + PIXEL01_3 + PIXEL02_4 + PIXEL12_3 + } + PIXEL10_C + PIXEL11 + PIXEL20_1D + PIXEL21_1 + PIXEL22_1M + break; + } + case 211: + { + PIXEL00_1L + PIXEL01_C + PIXEL02_1M + PIXEL10_1 + PIXEL11 + PIXEL20_1M + if (Diff(w[6], w[8])) + { + PIXEL12_C + PIXEL21_C + PIXEL22_C + } + else + { + PIXEL12_3 + PIXEL21_3 + PIXEL22_4 + } + break; + } + case 118: + { + PIXEL00_1M + if (Diff(w[2], w[6])) + { + PIXEL01_C + PIXEL02_C + PIXEL12_C + } + else + { + PIXEL01_3 + PIXEL02_4 + PIXEL12_3 + } + PIXEL10_1 + PIXEL11 + PIXEL20_1L + PIXEL21_C + PIXEL22_1M + break; + } + case 217: + { + PIXEL00_1U + PIXEL01_1 + PIXEL02_1M + PIXEL10_C + PIXEL11 + PIXEL20_1M + if (Diff(w[6], w[8])) + { + PIXEL12_C + PIXEL21_C + PIXEL22_C + } + else + { + PIXEL12_3 + PIXEL21_3 + PIXEL22_4 + } + break; + } + case 110: + { + PIXEL00_1M + PIXEL01_C + PIXEL02_1R + PIXEL11 + PIXEL12_1 + if (Diff(w[8], w[4])) + { + PIXEL10_C + PIXEL20_C + PIXEL21_C + } + else + { + PIXEL10_3 + PIXEL20_4 + PIXEL21_3 + } + PIXEL22_1M + break; + } + case 155: + { + if (Diff(w[4], w[2])) + { + PIXEL00_C + PIXEL01_C + PIXEL10_C + } + else + { + PIXEL00_4 + PIXEL01_3 + PIXEL10_3 + } + PIXEL02_1M + PIXEL11 + PIXEL12_C + PIXEL20_1M + PIXEL21_1 + PIXEL22_1D + break; + } + case 188: + { + PIXEL00_1M + PIXEL01_1 + PIXEL02_1U + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1D + PIXEL21_1 + PIXEL22_1D + break; + } + case 185: + { + PIXEL00_1U + PIXEL01_1 + PIXEL02_1M + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1D + PIXEL21_1 + PIXEL22_1D + break; + } + case 61: + { + PIXEL00_1U + PIXEL01_1 + PIXEL02_1U + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1D + PIXEL21_1 + PIXEL22_1M + break; + } + case 157: + { + PIXEL00_1U + PIXEL01_1 + PIXEL02_1U + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1M + PIXEL21_1 + PIXEL22_1D + break; + } + case 103: + { + PIXEL00_1L + PIXEL01_C + PIXEL02_1R + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1L + PIXEL21_C + PIXEL22_1M + break; + } + case 227: + { + PIXEL00_1L + PIXEL01_C + PIXEL02_1M + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1L + PIXEL21_C + PIXEL22_1R + break; + } + case 230: + { + PIXEL00_1M + PIXEL01_C + PIXEL02_1R + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1L + PIXEL21_C + PIXEL22_1R + break; + } + case 199: + { + PIXEL00_1L + PIXEL01_C + PIXEL02_1R + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_C + PIXEL22_1R + break; + } + case 220: + { + PIXEL00_1M + PIXEL01_1 + PIXEL02_1U + PIXEL10_C + PIXEL11 + if (Diff(w[8], w[4])) + { + PIXEL20_1M + } + else + { + PIXEL20_2 + } + if (Diff(w[6], w[8])) + { + PIXEL12_C + PIXEL21_C + PIXEL22_C + } + else + { + PIXEL12_3 + PIXEL21_3 + PIXEL22_4 + } + break; + } + case 158: + { + if (Diff(w[4], w[2])) + { + PIXEL00_1M + } + else + { + PIXEL00_2 + } + if (Diff(w[2], w[6])) + { + PIXEL01_C + PIXEL02_C + PIXEL12_C + } + else + { + PIXEL01_3 + PIXEL02_4 + PIXEL12_3 + } + PIXEL10_C + PIXEL11 + PIXEL20_1M + PIXEL21_1 + PIXEL22_1D + break; + } + case 234: + { + if (Diff(w[4], w[2])) + { + PIXEL00_1M + } + else + { + PIXEL00_2 + } + PIXEL01_C + PIXEL02_1M + PIXEL11 + PIXEL12_1 + if (Diff(w[8], w[4])) + { + PIXEL10_C + PIXEL20_C + PIXEL21_C + } + else + { + PIXEL10_3 + PIXEL20_4 + PIXEL21_3 + } + PIXEL22_1R + break; + } + case 242: + { + PIXEL00_1M + PIXEL01_C + if (Diff(w[2], w[6])) + { + PIXEL02_1M + } + else + { + PIXEL02_2 + } + PIXEL10_1 + PIXEL11 + PIXEL20_1L + if (Diff(w[6], w[8])) + { + PIXEL12_C + PIXEL21_C + PIXEL22_C + } + else + { + PIXEL12_3 + PIXEL21_3 + PIXEL22_4 + } + break; + } + case 59: + { + if (Diff(w[4], w[2])) + { + PIXEL00_C + PIXEL01_C + PIXEL10_C + } + else + { + PIXEL00_4 + PIXEL01_3 + PIXEL10_3 + } + if (Diff(w[2], w[6])) + { + PIXEL02_1M + } + else + { + PIXEL02_2 + } + PIXEL11 + PIXEL12_C + PIXEL20_1D + PIXEL21_1 + PIXEL22_1M + break; + } + case 121: + { + PIXEL00_1U + PIXEL01_1 + PIXEL02_1M + PIXEL11 + PIXEL12_C + if (Diff(w[8], w[4])) + { + PIXEL10_C + PIXEL20_C + PIXEL21_C + } + else + { + PIXEL10_3 + PIXEL20_4 + PIXEL21_3 + } + if (Diff(w[6], w[8])) + { + PIXEL22_1M + } + else + { + PIXEL22_2 + } + break; + } + case 87: + { + PIXEL00_1L + if (Diff(w[2], w[6])) + { + PIXEL01_C + PIXEL02_C + PIXEL12_C + } + else + { + PIXEL01_3 + PIXEL02_4 + PIXEL12_3 + } + PIXEL10_1 + PIXEL11 + PIXEL20_1M + PIXEL21_C + if (Diff(w[6], w[8])) + { + PIXEL22_1M + } + else + { + PIXEL22_2 + } + break; + } + case 79: + { + if (Diff(w[4], w[2])) + { + PIXEL00_C + PIXEL01_C + PIXEL10_C + } + else + { + PIXEL00_4 + PIXEL01_3 + PIXEL10_3 + } + PIXEL02_1R + PIXEL11 + PIXEL12_1 + if (Diff(w[8], w[4])) + { + PIXEL20_1M + } + else + { + PIXEL20_2 + } + PIXEL21_C + PIXEL22_1M + break; + } + case 122: + { + if (Diff(w[4], w[2])) + { + PIXEL00_1M + } + else + { + PIXEL00_2 + } + PIXEL01_C + if (Diff(w[2], w[6])) + { + PIXEL02_1M + } + else + { + PIXEL02_2 + } + PIXEL11 + PIXEL12_C + if (Diff(w[8], w[4])) + { + PIXEL10_C + PIXEL20_C + PIXEL21_C + } + else + { + PIXEL10_3 + PIXEL20_4 + PIXEL21_3 + } + if (Diff(w[6], w[8])) + { + PIXEL22_1M + } + else + { + PIXEL22_2 + } + break; + } + case 94: + { + if (Diff(w[4], w[2])) + { + PIXEL00_1M + } + else + { + PIXEL00_2 + } + if (Diff(w[2], w[6])) + { + PIXEL01_C + PIXEL02_C + PIXEL12_C + } + else + { + PIXEL01_3 + PIXEL02_4 + PIXEL12_3 + } + PIXEL10_C + PIXEL11 + if (Diff(w[8], w[4])) + { + PIXEL20_1M + } + else + { + PIXEL20_2 + } + PIXEL21_C + if (Diff(w[6], w[8])) + { + PIXEL22_1M + } + else + { + PIXEL22_2 + } + break; + } + case 218: + { + if (Diff(w[4], w[2])) + { + PIXEL00_1M + } + else + { + PIXEL00_2 + } + PIXEL01_C + if (Diff(w[2], w[6])) + { + PIXEL02_1M + } + else + { + PIXEL02_2 + } + PIXEL10_C + PIXEL11 + if (Diff(w[8], w[4])) + { + PIXEL20_1M + } + else + { + PIXEL20_2 + } + if (Diff(w[6], w[8])) + { + PIXEL12_C + PIXEL21_C + PIXEL22_C + } + else + { + PIXEL12_3 + PIXEL21_3 + PIXEL22_4 + } + break; + } + case 91: + { + if (Diff(w[4], w[2])) + { + PIXEL00_C + PIXEL01_C + PIXEL10_C + } + else + { + PIXEL00_4 + PIXEL01_3 + PIXEL10_3 + } + if (Diff(w[2], w[6])) + { + PIXEL02_1M + } + else + { + PIXEL02_2 + } + PIXEL11 + PIXEL12_C + if (Diff(w[8], w[4])) + { + PIXEL20_1M + } + else + { + PIXEL20_2 + } + PIXEL21_C + if (Diff(w[6], w[8])) + { + PIXEL22_1M + } + else + { + PIXEL22_2 + } + break; + } + case 229: + { + PIXEL00_2 + PIXEL01_1 + PIXEL02_2 + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1L + PIXEL21_C + PIXEL22_1R + break; + } + case 167: + { + PIXEL00_1L + PIXEL01_C + PIXEL02_1R + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_2 + PIXEL21_1 + PIXEL22_2 + break; + } + case 173: + { + PIXEL00_1U + PIXEL01_1 + PIXEL02_2 + PIXEL10_C + PIXEL11 + PIXEL12_1 + PIXEL20_1D + PIXEL21_1 + PIXEL22_2 + break; + } + case 181: + { + PIXEL00_2 + PIXEL01_1 + PIXEL02_1U + PIXEL10_1 + PIXEL11 + PIXEL12_C + PIXEL20_2 + PIXEL21_1 + PIXEL22_1D + break; + } + case 186: + { + if (Diff(w[4], w[2])) + { + PIXEL00_1M + } + else + { + PIXEL00_2 + } + PIXEL01_C + if (Diff(w[2], w[6])) + { + PIXEL02_1M + } + else + { + PIXEL02_2 + } + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1D + PIXEL21_1 + PIXEL22_1D + break; + } + case 115: + { + PIXEL00_1L + PIXEL01_C + if (Diff(w[2], w[6])) + { + PIXEL02_1M + } + else + { + PIXEL02_2 + } + PIXEL10_1 + PIXEL11 + PIXEL12_C + PIXEL20_1L + PIXEL21_C + if (Diff(w[6], w[8])) + { + PIXEL22_1M + } + else + { + PIXEL22_2 + } + break; + } + case 93: + { + PIXEL00_1U + PIXEL01_1 + PIXEL02_1U + PIXEL10_C + PIXEL11 + PIXEL12_C + if (Diff(w[8], w[4])) + { + PIXEL20_1M + } + else + { + PIXEL20_2 + } + PIXEL21_C + if (Diff(w[6], w[8])) + { + PIXEL22_1M + } + else + { + PIXEL22_2 + } + break; + } + case 206: + { + if (Diff(w[4], w[2])) + { + PIXEL00_1M + } + else + { + PIXEL00_2 + } + PIXEL01_C + PIXEL02_1R + PIXEL10_C + PIXEL11 + PIXEL12_1 + if (Diff(w[8], w[4])) + { + PIXEL20_1M + } + else + { + PIXEL20_2 + } + PIXEL21_C + PIXEL22_1R + break; + } + case 205: + case 201: + { + PIXEL00_1U + PIXEL01_1 + PIXEL02_2 + PIXEL10_C + PIXEL11 + PIXEL12_1 + if (Diff(w[8], w[4])) + { + PIXEL20_1M + } + else + { + PIXEL20_2 + } + PIXEL21_C + PIXEL22_1R + break; + } + case 174: + case 46: + { + if (Diff(w[4], w[2])) + { + PIXEL00_1M + } + else + { + PIXEL00_2 + } + PIXEL01_C + PIXEL02_1R + PIXEL10_C + PIXEL11 + PIXEL12_1 + PIXEL20_1D + PIXEL21_1 + PIXEL22_2 + break; + } + case 179: + case 147: + { + PIXEL00_1L + PIXEL01_C + if (Diff(w[2], w[6])) + { + PIXEL02_1M + } + else + { + PIXEL02_2 + } + PIXEL10_1 + PIXEL11 + PIXEL12_C + PIXEL20_2 + PIXEL21_1 + PIXEL22_1D + break; + } + case 117: + case 116: + { + PIXEL00_2 + PIXEL01_1 + PIXEL02_1U + PIXEL10_1 + PIXEL11 + PIXEL12_C + PIXEL20_1L + PIXEL21_C + if (Diff(w[6], w[8])) + { + PIXEL22_1M + } + else + { + PIXEL22_2 + } + break; + } + case 189: + { + PIXEL00_1U + PIXEL01_1 + PIXEL02_1U + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1D + PIXEL21_1 + PIXEL22_1D + break; + } + case 231: + { + PIXEL00_1L + PIXEL01_C + PIXEL02_1R + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1L + PIXEL21_C + PIXEL22_1R + break; + } + case 126: + { + PIXEL00_1M + if (Diff(w[2], w[6])) + { + PIXEL01_C + PIXEL02_C + PIXEL12_C + } + else + { + PIXEL01_3 + PIXEL02_4 + PIXEL12_3 + } + PIXEL11 + if (Diff(w[8], w[4])) + { + PIXEL10_C + PIXEL20_C + PIXEL21_C + } + else + { + PIXEL10_3 + PIXEL20_4 + PIXEL21_3 + } + PIXEL22_1M + break; + } + case 219: + { + if (Diff(w[4], w[2])) + { + PIXEL00_C + PIXEL01_C + PIXEL10_C + } + else + { + PIXEL00_4 + PIXEL01_3 + PIXEL10_3 + } + PIXEL02_1M + PIXEL11 + PIXEL20_1M + if (Diff(w[6], w[8])) + { + PIXEL12_C + PIXEL21_C + PIXEL22_C + } + else + { + PIXEL12_3 + PIXEL21_3 + PIXEL22_4 + } + break; + } + case 125: + { + if (Diff(w[8], w[4])) + { + PIXEL00_1U + PIXEL10_C + PIXEL20_C + PIXEL21_C + } + else + { + PIXEL00_2 + PIXEL10_6 + PIXEL20_5 + PIXEL21_1 + } + PIXEL01_1 + PIXEL02_1U + PIXEL11 + PIXEL12_C + PIXEL22_1M + break; + } + case 221: + { + if (Diff(w[6], w[8])) + { + PIXEL02_1U + PIXEL12_C + PIXEL21_C + PIXEL22_C + } + else + { + PIXEL02_2 + PIXEL12_6 + PIXEL21_1 + PIXEL22_5 + } + PIXEL00_1U + PIXEL01_1 + PIXEL10_C + PIXEL11 + PIXEL20_1M + break; + } + case 207: + { + if (Diff(w[4], w[2])) + { + PIXEL00_C + PIXEL01_C + PIXEL02_1R + PIXEL10_C + } + else + { + PIXEL00_5 + PIXEL01_6 + PIXEL02_2 + PIXEL10_1 + } + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_C + PIXEL22_1R + break; + } + case 238: + { + if (Diff(w[8], w[4])) + { + PIXEL10_C + PIXEL20_C + PIXEL21_C + PIXEL22_1R + } + else + { + PIXEL10_1 + PIXEL20_5 + PIXEL21_6 + PIXEL22_2 + } + PIXEL00_1M + PIXEL01_C + PIXEL02_1R + PIXEL11 + PIXEL12_1 + break; + } + case 190: + { + if (Diff(w[2], w[6])) + { + PIXEL01_C + PIXEL02_C + PIXEL12_C + PIXEL22_1D + } + else + { + PIXEL01_1 + PIXEL02_5 + PIXEL12_6 + PIXEL22_2 + } + PIXEL00_1M + PIXEL10_C + PIXEL11 + PIXEL20_1D + PIXEL21_1 + break; + } + case 187: + { + if (Diff(w[4], w[2])) + { + PIXEL00_C + PIXEL01_C + PIXEL10_C + PIXEL20_1D + } + else + { + PIXEL00_5 + PIXEL01_1 + PIXEL10_6 + PIXEL20_2 + } + PIXEL02_1M + PIXEL11 + PIXEL12_C + PIXEL21_1 + PIXEL22_1D + break; + } + case 243: + { + if (Diff(w[6], w[8])) + { + PIXEL12_C + PIXEL20_1L + PIXEL21_C + PIXEL22_C + } + else + { + PIXEL12_1 + PIXEL20_2 + PIXEL21_6 + PIXEL22_5 + } + PIXEL00_1L + PIXEL01_C + PIXEL02_1M + PIXEL10_1 + PIXEL11 + break; + } + case 119: + { + if (Diff(w[2], w[6])) + { + PIXEL00_1L + PIXEL01_C + PIXEL02_C + PIXEL12_C + } + else + { + PIXEL00_2 + PIXEL01_6 + PIXEL02_5 + PIXEL12_1 + } + PIXEL10_1 + PIXEL11 + PIXEL20_1L + PIXEL21_C + PIXEL22_1M + break; + } + case 237: + case 233: + { + PIXEL00_1U + PIXEL01_1 + PIXEL02_2 + PIXEL10_C + PIXEL11 + PIXEL12_1 + if (Diff(w[8], w[4])) + { + PIXEL20_C + } + else + { + PIXEL20_2 + } + PIXEL21_C + PIXEL22_1R + break; + } + case 175: + case 47: + { + if (Diff(w[4], w[2])) + { + PIXEL00_C + } + else + { + PIXEL00_2 + } + PIXEL01_C + PIXEL02_1R + PIXEL10_C + PIXEL11 + PIXEL12_1 + PIXEL20_1D + PIXEL21_1 + PIXEL22_2 + break; + } + case 183: + case 151: + { + PIXEL00_1L + PIXEL01_C + if (Diff(w[2], w[6])) + { + PIXEL02_C + } + else + { + PIXEL02_2 + } + PIXEL10_1 + PIXEL11 + PIXEL12_C + PIXEL20_2 + PIXEL21_1 + PIXEL22_1D + break; + } + case 245: + case 244: + { + PIXEL00_2 + PIXEL01_1 + PIXEL02_1U + PIXEL10_1 + PIXEL11 + PIXEL12_C + PIXEL20_1L + PIXEL21_C + if (Diff(w[6], w[8])) + { + PIXEL22_C + } + else + { + PIXEL22_2 + } + break; + } + case 250: + { + PIXEL00_1M + PIXEL01_C + PIXEL02_1M + PIXEL11 + if (Diff(w[8], w[4])) + { + PIXEL10_C + PIXEL20_C + } + else + { + PIXEL10_3 + PIXEL20_4 + } + PIXEL21_C + if (Diff(w[6], w[8])) + { + PIXEL12_C + PIXEL22_C + } + else + { + PIXEL12_3 + PIXEL22_4 + } + break; + } + case 123: + { + if (Diff(w[4], w[2])) + { + PIXEL00_C + PIXEL01_C + } + else + { + PIXEL00_4 + PIXEL01_3 + } + PIXEL02_1M + PIXEL10_C + PIXEL11 + PIXEL12_C + if (Diff(w[8], w[4])) + { + PIXEL20_C + PIXEL21_C + } + else + { + PIXEL20_4 + PIXEL21_3 + } + PIXEL22_1M + break; + } + case 95: + { + if (Diff(w[4], w[2])) + { + PIXEL00_C + PIXEL10_C + } + else + { + PIXEL00_4 + PIXEL10_3 + } + PIXEL01_C + if (Diff(w[2], w[6])) + { + PIXEL02_C + PIXEL12_C + } + else + { + PIXEL02_4 + PIXEL12_3 + } + PIXEL11 + PIXEL20_1M + PIXEL21_C + PIXEL22_1M + break; + } + case 222: + { + PIXEL00_1M + if (Diff(w[2], w[6])) + { + PIXEL01_C + PIXEL02_C + } + else + { + PIXEL01_3 + PIXEL02_4 + } + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1M + if (Diff(w[6], w[8])) + { + PIXEL21_C + PIXEL22_C + } + else + { + PIXEL21_3 + PIXEL22_4 + } + break; + } + case 252: + { + PIXEL00_1M + PIXEL01_1 + PIXEL02_1U + PIXEL11 + PIXEL12_C + if (Diff(w[8], w[4])) + { + PIXEL10_C + PIXEL20_C + } + else + { + PIXEL10_3 + PIXEL20_4 + } + PIXEL21_C + if (Diff(w[6], w[8])) + { + PIXEL22_C + } + else + { + PIXEL22_2 + } + break; + } + case 249: + { + PIXEL00_1U + PIXEL01_1 + PIXEL02_1M + PIXEL10_C + PIXEL11 + if (Diff(w[8], w[4])) + { + PIXEL20_C + } + else + { + PIXEL20_2 + } + PIXEL21_C + if (Diff(w[6], w[8])) + { + PIXEL12_C + PIXEL22_C + } + else + { + PIXEL12_3 + PIXEL22_4 + } + break; + } + case 235: + { + if (Diff(w[4], w[2])) + { + PIXEL00_C + PIXEL01_C + } + else + { + PIXEL00_4 + PIXEL01_3 + } + PIXEL02_1M + PIXEL10_C + PIXEL11 + PIXEL12_1 + if (Diff(w[8], w[4])) + { + PIXEL20_C + } + else + { + PIXEL20_2 + } + PIXEL21_C + PIXEL22_1R + break; + } + case 111: + { + if (Diff(w[4], w[2])) + { + PIXEL00_C + } + else + { + PIXEL00_2 + } + PIXEL01_C + PIXEL02_1R + PIXEL10_C + PIXEL11 + PIXEL12_1 + if (Diff(w[8], w[4])) + { + PIXEL20_C + PIXEL21_C + } + else + { + PIXEL20_4 + PIXEL21_3 + } + PIXEL22_1M + break; + } + case 63: + { + if (Diff(w[4], w[2])) + { + PIXEL00_C + } + else + { + PIXEL00_2 + } + PIXEL01_C + if (Diff(w[2], w[6])) + { + PIXEL02_C + PIXEL12_C + } + else + { + PIXEL02_4 + PIXEL12_3 + } + PIXEL10_C + PIXEL11 + PIXEL20_1D + PIXEL21_1 + PIXEL22_1M + break; + } + case 159: + { + if (Diff(w[4], w[2])) + { + PIXEL00_C + PIXEL10_C + } + else + { + PIXEL00_4 + PIXEL10_3 + } + PIXEL01_C + if (Diff(w[2], w[6])) + { + PIXEL02_C + } + else + { + PIXEL02_2 + } + PIXEL11 + PIXEL12_C + PIXEL20_1M + PIXEL21_1 + PIXEL22_1D + break; + } + case 215: + { + PIXEL00_1L + PIXEL01_C + if (Diff(w[2], w[6])) + { + PIXEL02_C + } + else + { + PIXEL02_2 + } + PIXEL10_1 + PIXEL11 + PIXEL12_C + PIXEL20_1M + if (Diff(w[6], w[8])) + { + PIXEL21_C + PIXEL22_C + } + else + { + PIXEL21_3 + PIXEL22_4 + } + break; + } + case 246: + { + PIXEL00_1M + if (Diff(w[2], w[6])) + { + PIXEL01_C + PIXEL02_C + } + else + { + PIXEL01_3 + PIXEL02_4 + } + PIXEL10_1 + PIXEL11 + PIXEL12_C + PIXEL20_1L + PIXEL21_C + if (Diff(w[6], w[8])) + { + PIXEL22_C + } + else + { + PIXEL22_2 + } + break; + } + case 254: + { + PIXEL00_1M + if (Diff(w[2], w[6])) + { + PIXEL01_C + PIXEL02_C + } + else + { + PIXEL01_3 + PIXEL02_4 + } + PIXEL11 + if (Diff(w[8], w[4])) + { + PIXEL10_C + PIXEL20_C + } + else + { + PIXEL10_3 + PIXEL20_4 + } + if (Diff(w[6], w[8])) + { + PIXEL12_C + PIXEL21_C + PIXEL22_C + } + else + { + PIXEL12_3 + PIXEL21_3 + PIXEL22_2 + } + break; + } + case 253: + { + PIXEL00_1U + PIXEL01_1 + PIXEL02_1U + PIXEL10_C + PIXEL11 + PIXEL12_C + if (Diff(w[8], w[4])) + { + PIXEL20_C + } + else + { + PIXEL20_2 + } + PIXEL21_C + if (Diff(w[6], w[8])) + { + PIXEL22_C + } + else + { + PIXEL22_2 + } + break; + } + case 251: + { + if (Diff(w[4], w[2])) + { + PIXEL00_C + PIXEL01_C + } + else + { + PIXEL00_4 + PIXEL01_3 + } + PIXEL02_1M + PIXEL11 + if (Diff(w[8], w[4])) + { + PIXEL10_C + PIXEL20_C + PIXEL21_C + } + else + { + PIXEL10_3 + PIXEL20_2 + PIXEL21_3 + } + if (Diff(w[6], w[8])) + { + PIXEL12_C + PIXEL22_C + } + else + { + PIXEL12_3 + PIXEL22_4 + } + break; + } + case 239: + { + if (Diff(w[4], w[2])) + { + PIXEL00_C + } + else + { + PIXEL00_2 + } + PIXEL01_C + PIXEL02_1R + PIXEL10_C + PIXEL11 + PIXEL12_1 + if (Diff(w[8], w[4])) + { + PIXEL20_C + } + else + { + PIXEL20_2 + } + PIXEL21_C + PIXEL22_1R + break; + } + case 127: + { + if (Diff(w[4], w[2])) + { + PIXEL00_C + PIXEL01_C + PIXEL10_C + } + else + { + PIXEL00_2 + PIXEL01_3 + PIXEL10_3 + } + if (Diff(w[2], w[6])) + { + PIXEL02_C + PIXEL12_C + } + else + { + PIXEL02_4 + PIXEL12_3 + } + PIXEL11 + if (Diff(w[8], w[4])) + { + PIXEL20_C + PIXEL21_C + } + else + { + PIXEL20_4 + PIXEL21_3 + } + PIXEL22_1M + break; + } + case 191: + { + if (Diff(w[4], w[2])) + { + PIXEL00_C + } + else + { + PIXEL00_2 + } + PIXEL01_C + if (Diff(w[2], w[6])) + { + PIXEL02_C + } + else + { + PIXEL02_2 + } + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1D + PIXEL21_1 + PIXEL22_1D + break; + } + case 223: + { + if (Diff(w[4], w[2])) + { + PIXEL00_C + PIXEL10_C + } + else + { + PIXEL00_4 + PIXEL10_3 + } + if (Diff(w[2], w[6])) + { + PIXEL01_C + PIXEL02_C + PIXEL12_C + } + else + { + PIXEL01_3 + PIXEL02_2 + PIXEL12_3 + } + PIXEL11 + PIXEL20_1M + if (Diff(w[6], w[8])) + { + PIXEL21_C + PIXEL22_C + } + else + { + PIXEL21_3 + PIXEL22_4 + } + break; + } + case 247: + { + PIXEL00_1L + PIXEL01_C + if (Diff(w[2], w[6])) + { + PIXEL02_C + } + else + { + PIXEL02_2 + } + PIXEL10_1 + PIXEL11 + PIXEL12_C + PIXEL20_1L + PIXEL21_C + if (Diff(w[6], w[8])) + { + PIXEL22_C + } + else + { + PIXEL22_2 + } + break; + } + case 255: + { + if (Diff(w[4], w[2])) + { + PIXEL00_C + } + else + { + PIXEL00_2 + } + PIXEL01_C + if (Diff(w[2], w[6])) + { + PIXEL02_C + } + else + { + PIXEL02_2 + } + PIXEL10_C + PIXEL11 + PIXEL12_C + if (Diff(w[8], w[4])) + { + PIXEL20_C + } + else + { + PIXEL20_2 + } + PIXEL21_C + if (Diff(w[6], w[8])) + { + PIXEL22_C + } + else + { + PIXEL22_2 + } + break; + } + } + pIn+=2; + pOut+=12; + } + pOut+=BpL; + pOut+=BpL; + } +} + +void InitHQ3X(void) +{ + int i, j, k, r, g, b, Y, u, v; + + for (i=0; i<65536; i++) + LUT16to32[i] = ((i & 0xF800) << 8) + ((i & 0x07E0) << 5) + ((i & 0x001F) << 3); + + for (i=0; i<32; i++) + for (j=0; j<64; j++) + for (k=0; k<32; k++) + { + r = i << 3; + g = j << 2; + b = k << 3; + Y = (r + g + b) >> 2; + u = 128 + ((r - b) >> 2); + v = 128 + ((-r + 2*g -b)>>3); + RGBtoYUV[ (i << 11) + (j << 5) + k ] = (Y<<16) + (u<<8) + v; + } +} + diff --git a/engines/vileVN/external/hq3x/hq3x.h b/engines/vileVN/external/hq3x/hq3x.h new file mode 100644 index 0000000000..21966026f2 --- /dev/null +++ b/engines/vileVN/external/hq3x/hq3x.h @@ -0,0 +1,9 @@ +#ifndef _HQ3X_H_ +#define _HQ3X_H_ + +extern void InitHQ3X(void); +extern void hq3x_32(unsigned char *In, + unsigned char *Out,int Xres,int Yres,int BpL); + +#endif + diff --git a/engines/vileVN/external/hq4x/hq4x.cpp b/engines/vileVN/external/hq4x/hq4x.cpp new file mode 100644 index 0000000000..d0d2c0c372 --- /dev/null +++ b/engines/vileVN/external/hq4x/hq4x.cpp @@ -0,0 +1,5314 @@ +//hq4x filter demo program +//---------------------------------------------------------- +//Copyright (C) 2003 MaxSt ( maxst@hiend3d.com ) + +//This program is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This program is distributed in the hope that it will be useful, +//but WITHOUT ANY WARRANTY; without even the implied warranty of +//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +//Lesser General Public License for more details. +// +//You should have received a copy of the GNU Lesser General Public +//License along with this program; if not, write to the Free Software +//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +#include +#include +#include + +static int LUT16to32[65536]; +static int RGBtoYUV[65536]; +static int YUV1, YUV2; +const int Ymask = 0x00FF0000; +const int Umask = 0x0000FF00; +const int Vmask = 0x000000FF; +const int trY = 0x00300000; +const int trU = 0x00000700; +const int trV = 0x00000006; + +inline void Interp1(unsigned char * pc, int c1, int c2) +{ + *((int*)pc) = (c1*3+c2) >> 2; +} + +inline void Interp2(unsigned char * pc, int c1, int c2, int c3) +{ + *((int*)pc) = (c1*2+c2+c3) >> 2; +} + +inline void Interp3(unsigned char * pc, int c1, int c2) +{ + //*((int*)pc) = (c1*7+c2)/8; + + *((int*)pc) = ((((c1 & 0x00FF00)*7 + (c2 & 0x00FF00) ) & 0x0007F800) + + (((c1 & 0xFF00FF)*7 + (c2 & 0xFF00FF) ) & 0x07F807F8)) >> 3; +} + +inline void Interp5(unsigned char * pc, int c1, int c2) +{ + *((int*)pc) = (c1+c2) >> 1; +} + +inline void Interp6(unsigned char * pc, int c1, int c2, int c3) +{ + //*((int*)pc) = (c1*5+c2*2+c3)/8; + + *((int*)pc) = ((((c1 & 0x00FF00)*5 + (c2 & 0x00FF00)*2 + (c3 & 0x00FF00) ) & 0x0007F800) + + (((c1 & 0xFF00FF)*5 + (c2 & 0xFF00FF)*2 + (c3 & 0xFF00FF) ) & 0x07F807F8)) >> 3; +} + +inline void Interp7(unsigned char * pc, int c1, int c2, int c3) +{ + //*((int*)pc) = (c1*6+c2+c3)/8; + + *((int*)pc) = ((((c1 & 0x00FF00)*6 + (c2 & 0x00FF00) + (c3 & 0x00FF00) ) & 0x0007F800) + + (((c1 & 0xFF00FF)*6 + (c2 & 0xFF00FF) + (c3 & 0xFF00FF) ) & 0x07F807F8)) >> 3; +} + +inline void Interp8(unsigned char * pc, int c1, int c2) +{ + //*((int*)pc) = (c1*5+c2*3)/8; + + *((int*)pc) = ((((c1 & 0x00FF00)*5 + (c2 & 0x00FF00)*3 ) & 0x0007F800) + + (((c1 & 0xFF00FF)*5 + (c2 & 0xFF00FF)*3 ) & 0x07F807F8)) >> 3; +} + +#define PIXEL00_0 *((int*)(pOut)) = c[5]; +#define PIXEL00_11 Interp1(pOut, c[5], c[4]); +#define PIXEL00_12 Interp1(pOut, c[5], c[2]); +#define PIXEL00_20 Interp2(pOut, c[5], c[2], c[4]); +#define PIXEL00_50 Interp5(pOut, c[2], c[4]); +#define PIXEL00_80 Interp8(pOut, c[5], c[1]); +#define PIXEL00_81 Interp8(pOut, c[5], c[4]); +#define PIXEL00_82 Interp8(pOut, c[5], c[2]); +#define PIXEL01_0 *((int*)(pOut+4)) = c[5]; +#define PIXEL01_10 Interp1(pOut+4, c[5], c[1]); +#define PIXEL01_12 Interp1(pOut+4, c[5], c[2]); +#define PIXEL01_14 Interp1(pOut+4, c[2], c[5]); +#define PIXEL01_21 Interp2(pOut+4, c[2], c[5], c[4]); +#define PIXEL01_31 Interp3(pOut+4, c[5], c[4]); +#define PIXEL01_50 Interp5(pOut+4, c[2], c[5]); +#define PIXEL01_60 Interp6(pOut+4, c[5], c[2], c[4]); +#define PIXEL01_61 Interp6(pOut+4, c[5], c[2], c[1]); +#define PIXEL01_82 Interp8(pOut+4, c[5], c[2]); +#define PIXEL01_83 Interp8(pOut+4, c[2], c[4]); +#define PIXEL02_0 *((int*)(pOut+8)) = c[5]; +#define PIXEL02_10 Interp1(pOut+8, c[5], c[3]); +#define PIXEL02_11 Interp1(pOut+8, c[5], c[2]); +#define PIXEL02_13 Interp1(pOut+8, c[2], c[5]); +#define PIXEL02_21 Interp2(pOut+8, c[2], c[5], c[6]); +#define PIXEL02_32 Interp3(pOut+8, c[5], c[6]); +#define PIXEL02_50 Interp5(pOut+8, c[2], c[5]); +#define PIXEL02_60 Interp6(pOut+8, c[5], c[2], c[6]); +#define PIXEL02_61 Interp6(pOut+8, c[5], c[2], c[3]); +#define PIXEL02_81 Interp8(pOut+8, c[5], c[2]); +#define PIXEL02_83 Interp8(pOut+8, c[2], c[6]); +#define PIXEL03_0 *((int*)(pOut+12)) = c[5]; +#define PIXEL03_11 Interp1(pOut+12, c[5], c[2]); +#define PIXEL03_12 Interp1(pOut+12, c[5], c[6]); +#define PIXEL03_20 Interp2(pOut+12, c[5], c[2], c[6]); +#define PIXEL03_50 Interp5(pOut+12, c[2], c[6]); +#define PIXEL03_80 Interp8(pOut+12, c[5], c[3]); +#define PIXEL03_81 Interp8(pOut+12, c[5], c[2]); +#define PIXEL03_82 Interp8(pOut+12, c[5], c[6]); +#define PIXEL10_0 *((int*)(pOut+BpL)) = c[5]; +#define PIXEL10_10 Interp1(pOut+BpL, c[5], c[1]); +#define PIXEL10_11 Interp1(pOut+BpL, c[5], c[4]); +#define PIXEL10_13 Interp1(pOut+BpL, c[4], c[5]); +#define PIXEL10_21 Interp2(pOut+BpL, c[4], c[5], c[2]); +#define PIXEL10_32 Interp3(pOut+BpL, c[5], c[2]); +#define PIXEL10_50 Interp5(pOut+BpL, c[4], c[5]); +#define PIXEL10_60 Interp6(pOut+BpL, c[5], c[4], c[2]); +#define PIXEL10_61 Interp6(pOut+BpL, c[5], c[4], c[1]); +#define PIXEL10_81 Interp8(pOut+BpL, c[5], c[4]); +#define PIXEL10_83 Interp8(pOut+BpL, c[4], c[2]); +#define PIXEL11_0 *((int*)(pOut+BpL+4)) = c[5]; +#define PIXEL11_30 Interp3(pOut+BpL+4, c[5], c[1]); +#define PIXEL11_31 Interp3(pOut+BpL+4, c[5], c[4]); +#define PIXEL11_32 Interp3(pOut+BpL+4, c[5], c[2]); +#define PIXEL11_70 Interp7(pOut+BpL+4, c[5], c[4], c[2]); +#define PIXEL12_0 *((int*)(pOut+BpL+8)) = c[5]; +#define PIXEL12_30 Interp3(pOut+BpL+8, c[5], c[3]); +#define PIXEL12_31 Interp3(pOut+BpL+8, c[5], c[2]); +#define PIXEL12_32 Interp3(pOut+BpL+8, c[5], c[6]); +#define PIXEL12_70 Interp7(pOut+BpL+8, c[5], c[6], c[2]); +#define PIXEL13_0 *((int*)(pOut+BpL+12)) = c[5]; +#define PIXEL13_10 Interp1(pOut+BpL+12, c[5], c[3]); +#define PIXEL13_12 Interp1(pOut+BpL+12, c[5], c[6]); +#define PIXEL13_14 Interp1(pOut+BpL+12, c[6], c[5]); +#define PIXEL13_21 Interp2(pOut+BpL+12, c[6], c[5], c[2]); +#define PIXEL13_31 Interp3(pOut+BpL+12, c[5], c[2]); +#define PIXEL13_50 Interp5(pOut+BpL+12, c[6], c[5]); +#define PIXEL13_60 Interp6(pOut+BpL+12, c[5], c[6], c[2]); +#define PIXEL13_61 Interp6(pOut+BpL+12, c[5], c[6], c[3]); +#define PIXEL13_82 Interp8(pOut+BpL+12, c[5], c[6]); +#define PIXEL13_83 Interp8(pOut+BpL+12, c[6], c[2]); +#define PIXEL20_0 *((int*)(pOut+BpL+BpL)) = c[5]; +#define PIXEL20_10 Interp1(pOut+BpL+BpL, c[5], c[7]); +#define PIXEL20_12 Interp1(pOut+BpL+BpL, c[5], c[4]); +#define PIXEL20_14 Interp1(pOut+BpL+BpL, c[4], c[5]); +#define PIXEL20_21 Interp2(pOut+BpL+BpL, c[4], c[5], c[8]); +#define PIXEL20_31 Interp3(pOut+BpL+BpL, c[5], c[8]); +#define PIXEL20_50 Interp5(pOut+BpL+BpL, c[4], c[5]); +#define PIXEL20_60 Interp6(pOut+BpL+BpL, c[5], c[4], c[8]); +#define PIXEL20_61 Interp6(pOut+BpL+BpL, c[5], c[4], c[7]); +#define PIXEL20_82 Interp8(pOut+BpL+BpL, c[5], c[4]); +#define PIXEL20_83 Interp8(pOut+BpL+BpL, c[4], c[8]); +#define PIXEL21_0 *((int*)(pOut+BpL+BpL+4)) = c[5]; +#define PIXEL21_30 Interp3(pOut+BpL+BpL+4, c[5], c[7]); +#define PIXEL21_31 Interp3(pOut+BpL+BpL+4, c[5], c[8]); +#define PIXEL21_32 Interp3(pOut+BpL+BpL+4, c[5], c[4]); +#define PIXEL21_70 Interp7(pOut+BpL+BpL+4, c[5], c[4], c[8]); +#define PIXEL22_0 *((int*)(pOut+BpL+BpL+8)) = c[5]; +#define PIXEL22_30 Interp3(pOut+BpL+BpL+8, c[5], c[9]); +#define PIXEL22_31 Interp3(pOut+BpL+BpL+8, c[5], c[6]); +#define PIXEL22_32 Interp3(pOut+BpL+BpL+8, c[5], c[8]); +#define PIXEL22_70 Interp7(pOut+BpL+BpL+8, c[5], c[6], c[8]); +#define PIXEL23_0 *((int*)(pOut+BpL+BpL+12)) = c[5]; +#define PIXEL23_10 Interp1(pOut+BpL+BpL+12, c[5], c[9]); +#define PIXEL23_11 Interp1(pOut+BpL+BpL+12, c[5], c[6]); +#define PIXEL23_13 Interp1(pOut+BpL+BpL+12, c[6], c[5]); +#define PIXEL23_21 Interp2(pOut+BpL+BpL+12, c[6], c[5], c[8]); +#define PIXEL23_32 Interp3(pOut+BpL+BpL+12, c[5], c[8]); +#define PIXEL23_50 Interp5(pOut+BpL+BpL+12, c[6], c[5]); +#define PIXEL23_60 Interp6(pOut+BpL+BpL+12, c[5], c[6], c[8]); +#define PIXEL23_61 Interp6(pOut+BpL+BpL+12, c[5], c[6], c[9]); +#define PIXEL23_81 Interp8(pOut+BpL+BpL+12, c[5], c[6]); +#define PIXEL23_83 Interp8(pOut+BpL+BpL+12, c[6], c[8]); +#define PIXEL30_0 *((int*)(pOut+BpL+BpL+BpL)) = c[5]; +#define PIXEL30_11 Interp1(pOut+BpL+BpL+BpL, c[5], c[8]); +#define PIXEL30_12 Interp1(pOut+BpL+BpL+BpL, c[5], c[4]); +#define PIXEL30_20 Interp2(pOut+BpL+BpL+BpL, c[5], c[8], c[4]); +#define PIXEL30_50 Interp5(pOut+BpL+BpL+BpL, c[8], c[4]); +#define PIXEL30_80 Interp8(pOut+BpL+BpL+BpL, c[5], c[7]); +#define PIXEL30_81 Interp8(pOut+BpL+BpL+BpL, c[5], c[8]); +#define PIXEL30_82 Interp8(pOut+BpL+BpL+BpL, c[5], c[4]); +#define PIXEL31_0 *((int*)(pOut+BpL+BpL+BpL+4)) = c[5]; +#define PIXEL31_10 Interp1(pOut+BpL+BpL+BpL+4, c[5], c[7]); +#define PIXEL31_11 Interp1(pOut+BpL+BpL+BpL+4, c[5], c[8]); +#define PIXEL31_13 Interp1(pOut+BpL+BpL+BpL+4, c[8], c[5]); +#define PIXEL31_21 Interp2(pOut+BpL+BpL+BpL+4, c[8], c[5], c[4]); +#define PIXEL31_32 Interp3(pOut+BpL+BpL+BpL+4, c[5], c[4]); +#define PIXEL31_50 Interp5(pOut+BpL+BpL+BpL+4, c[8], c[5]); +#define PIXEL31_60 Interp6(pOut+BpL+BpL+BpL+4, c[5], c[8], c[4]); +#define PIXEL31_61 Interp6(pOut+BpL+BpL+BpL+4, c[5], c[8], c[7]); +#define PIXEL31_81 Interp8(pOut+BpL+BpL+BpL+4, c[5], c[8]); +#define PIXEL31_83 Interp8(pOut+BpL+BpL+BpL+4, c[8], c[4]); +#define PIXEL32_0 *((int*)(pOut+BpL+BpL+BpL+8)) = c[5]; +#define PIXEL32_10 Interp1(pOut+BpL+BpL+BpL+8, c[5], c[9]); +#define PIXEL32_12 Interp1(pOut+BpL+BpL+BpL+8, c[5], c[8]); +#define PIXEL32_14 Interp1(pOut+BpL+BpL+BpL+8, c[8], c[5]); +#define PIXEL32_21 Interp2(pOut+BpL+BpL+BpL+8, c[8], c[5], c[6]); +#define PIXEL32_31 Interp3(pOut+BpL+BpL+BpL+8, c[5], c[6]); +#define PIXEL32_50 Interp5(pOut+BpL+BpL+BpL+8, c[8], c[5]); +#define PIXEL32_60 Interp6(pOut+BpL+BpL+BpL+8, c[5], c[8], c[6]); +#define PIXEL32_61 Interp6(pOut+BpL+BpL+BpL+8, c[5], c[8], c[9]); +#define PIXEL32_82 Interp8(pOut+BpL+BpL+BpL+8, c[5], c[8]); +#define PIXEL32_83 Interp8(pOut+BpL+BpL+BpL+8, c[8], c[6]); +#define PIXEL33_0 *((int*)(pOut+BpL+BpL+BpL+12)) = c[5]; +#define PIXEL33_11 Interp1(pOut+BpL+BpL+BpL+12, c[5], c[6]); +#define PIXEL33_12 Interp1(pOut+BpL+BpL+BpL+12, c[5], c[8]); +#define PIXEL33_20 Interp2(pOut+BpL+BpL+BpL+12, c[5], c[8], c[6]); +#define PIXEL33_50 Interp5(pOut+BpL+BpL+BpL+12, c[8], c[6]); +#define PIXEL33_80 Interp8(pOut+BpL+BpL+BpL+12, c[5], c[9]); +#define PIXEL33_81 Interp8(pOut+BpL+BpL+BpL+12, c[5], c[6]); +#define PIXEL33_82 Interp8(pOut+BpL+BpL+BpL+12, c[5], c[8]); + + + +inline bool Diff(unsigned int w1, unsigned int w2) +{ + YUV1 = RGBtoYUV[w1]; + YUV2 = RGBtoYUV[w2]; + return ( ( abs((YUV1 & Ymask) - (YUV2 & Ymask)) > trY ) || + ( abs((YUV1 & Umask) - (YUV2 & Umask)) > trU ) || + ( abs((YUV1 & Vmask) - (YUV2 & Vmask)) > trV ) ); +} + +void hq4x_32( unsigned char * pIn, unsigned char * pOut, int Xres, int Yres, int BpL ) +{ + int i, j, k; + int prevline, nextline; + int w[10]; + int c[10]; + + // +----+----+----+ + // | | | | + // | w1 | w2 | w3 | + // +----+----+----+ + // | | | | + // | w4 | w5 | w6 | + // +----+----+----+ + // | | | | + // | w7 | w8 | w9 | + // +----+----+----+ + + for (j=0; j0) prevline = -Xres*2; else prevline = 0; + if (j0) + { + w[1] = *((unsigned short*)(pIn + prevline - 2)); + w[4] = *((unsigned short*)(pIn - 2)); + w[7] = *((unsigned short*)(pIn + nextline - 2)); + } + else + { + w[1] = w[2]; + w[4] = w[5]; + w[7] = w[8]; + } + + if (i trY ) || + ( abs((YUV1 & Umask) - (YUV2 & Umask)) > trU ) || + ( abs((YUV1 & Vmask) - (YUV2 & Vmask)) > trV ) ) + pattern |= flag; + } + flag <<= 1; + } + + for (k=1; k<=9; k++) + c[k] = LUT16to32[w[k]]; + + switch (pattern) + { + case 0: + case 1: + case 4: + case 32: + case 128: + case 5: + case 132: + case 160: + case 33: + case 129: + case 36: + case 133: + case 164: + case 161: + case 37: + case 165: + { + PIXEL00_20 + PIXEL01_60 + PIXEL02_60 + PIXEL03_20 + PIXEL10_60 + PIXEL11_70 + PIXEL12_70 + PIXEL13_60 + PIXEL20_60 + PIXEL21_70 + PIXEL22_70 + PIXEL23_60 + PIXEL30_20 + PIXEL31_60 + PIXEL32_60 + PIXEL33_20 + break; + } + case 2: + case 34: + case 130: + case 162: + { + PIXEL00_80 + PIXEL01_10 + PIXEL02_10 + PIXEL03_80 + PIXEL10_61 + PIXEL11_30 + PIXEL12_30 + PIXEL13_61 + PIXEL20_60 + PIXEL21_70 + PIXEL22_70 + PIXEL23_60 + PIXEL30_20 + PIXEL31_60 + PIXEL32_60 + PIXEL33_20 + break; + } + case 16: + case 17: + case 48: + case 49: + { + PIXEL00_20 + PIXEL01_60 + PIXEL02_61 + PIXEL03_80 + PIXEL10_60 + PIXEL11_70 + PIXEL12_30 + PIXEL13_10 + PIXEL20_60 + PIXEL21_70 + PIXEL22_30 + PIXEL23_10 + PIXEL30_20 + PIXEL31_60 + PIXEL32_61 + PIXEL33_80 + break; + } + case 64: + case 65: + case 68: + case 69: + { + PIXEL00_20 + PIXEL01_60 + PIXEL02_60 + PIXEL03_20 + PIXEL10_60 + PIXEL11_70 + PIXEL12_70 + PIXEL13_60 + PIXEL20_61 + PIXEL21_30 + PIXEL22_30 + PIXEL23_61 + PIXEL30_80 + PIXEL31_10 + PIXEL32_10 + PIXEL33_80 + break; + } + case 8: + case 12: + case 136: + case 140: + { + PIXEL00_80 + PIXEL01_61 + PIXEL02_60 + PIXEL03_20 + PIXEL10_10 + PIXEL11_30 + PIXEL12_70 + PIXEL13_60 + PIXEL20_10 + PIXEL21_30 + PIXEL22_70 + PIXEL23_60 + PIXEL30_80 + PIXEL31_61 + PIXEL32_60 + PIXEL33_20 + break; + } + case 3: + case 35: + case 131: + case 163: + { + PIXEL00_81 + PIXEL01_31 + PIXEL02_10 + PIXEL03_80 + PIXEL10_81 + PIXEL11_31 + PIXEL12_30 + PIXEL13_61 + PIXEL20_60 + PIXEL21_70 + PIXEL22_70 + PIXEL23_60 + PIXEL30_20 + PIXEL31_60 + PIXEL32_60 + PIXEL33_20 + break; + } + case 6: + case 38: + case 134: + case 166: + { + PIXEL00_80 + PIXEL01_10 + PIXEL02_32 + PIXEL03_82 + PIXEL10_61 + PIXEL11_30 + PIXEL12_32 + PIXEL13_82 + PIXEL20_60 + PIXEL21_70 + PIXEL22_70 + PIXEL23_60 + PIXEL30_20 + PIXEL31_60 + PIXEL32_60 + PIXEL33_20 + break; + } + case 20: + case 21: + case 52: + case 53: + { + PIXEL00_20 + PIXEL01_60 + PIXEL02_81 + PIXEL03_81 + PIXEL10_60 + PIXEL11_70 + PIXEL12_31 + PIXEL13_31 + PIXEL20_60 + PIXEL21_70 + PIXEL22_30 + PIXEL23_10 + PIXEL30_20 + PIXEL31_60 + PIXEL32_61 + PIXEL33_80 + break; + } + case 144: + case 145: + case 176: + case 177: + { + PIXEL00_20 + PIXEL01_60 + PIXEL02_61 + PIXEL03_80 + PIXEL10_60 + PIXEL11_70 + PIXEL12_30 + PIXEL13_10 + PIXEL20_60 + PIXEL21_70 + PIXEL22_32 + PIXEL23_32 + PIXEL30_20 + PIXEL31_60 + PIXEL32_82 + PIXEL33_82 + break; + } + case 192: + case 193: + case 196: + case 197: + { + PIXEL00_20 + PIXEL01_60 + PIXEL02_60 + PIXEL03_20 + PIXEL10_60 + PIXEL11_70 + PIXEL12_70 + PIXEL13_60 + PIXEL20_61 + PIXEL21_30 + PIXEL22_31 + PIXEL23_81 + PIXEL30_80 + PIXEL31_10 + PIXEL32_31 + PIXEL33_81 + break; + } + case 96: + case 97: + case 100: + case 101: + { + PIXEL00_20 + PIXEL01_60 + PIXEL02_60 + PIXEL03_20 + PIXEL10_60 + PIXEL11_70 + PIXEL12_70 + PIXEL13_60 + PIXEL20_82 + PIXEL21_32 + PIXEL22_30 + PIXEL23_61 + PIXEL30_82 + PIXEL31_32 + PIXEL32_10 + PIXEL33_80 + break; + } + case 40: + case 44: + case 168: + case 172: + { + PIXEL00_80 + PIXEL01_61 + PIXEL02_60 + PIXEL03_20 + PIXEL10_10 + PIXEL11_30 + PIXEL12_70 + PIXEL13_60 + PIXEL20_31 + PIXEL21_31 + PIXEL22_70 + PIXEL23_60 + PIXEL30_81 + PIXEL31_81 + PIXEL32_60 + PIXEL33_20 + break; + } + case 9: + case 13: + case 137: + case 141: + { + PIXEL00_82 + PIXEL01_82 + PIXEL02_60 + PIXEL03_20 + PIXEL10_32 + PIXEL11_32 + PIXEL12_70 + PIXEL13_60 + PIXEL20_10 + PIXEL21_30 + PIXEL22_70 + PIXEL23_60 + PIXEL30_80 + PIXEL31_61 + PIXEL32_60 + PIXEL33_20 + break; + } + case 18: + case 50: + { + PIXEL00_80 + PIXEL01_10 + if (Diff(w[2], w[6])) + { + PIXEL02_10 + PIXEL03_80 + PIXEL12_30 + PIXEL13_10 + } + else + { + PIXEL02_50 + PIXEL03_50 + PIXEL12_0 + PIXEL13_50 + } + PIXEL10_61 + PIXEL11_30 + PIXEL20_60 + PIXEL21_70 + PIXEL22_30 + PIXEL23_10 + PIXEL30_20 + PIXEL31_60 + PIXEL32_61 + PIXEL33_80 + break; + } + case 80: + case 81: + { + PIXEL00_20 + PIXEL01_60 + PIXEL02_61 + PIXEL03_80 + PIXEL10_60 + PIXEL11_70 + PIXEL12_30 + PIXEL13_10 + PIXEL20_61 + PIXEL21_30 + if (Diff(w[6], w[8])) + { + PIXEL22_30 + PIXEL23_10 + PIXEL32_10 + PIXEL33_80 + } + else + { + PIXEL22_0 + PIXEL23_50 + PIXEL32_50 + PIXEL33_50 + } + PIXEL30_80 + PIXEL31_10 + break; + } + case 72: + case 76: + { + PIXEL00_80 + PIXEL01_61 + PIXEL02_60 + PIXEL03_20 + PIXEL10_10 + PIXEL11_30 + PIXEL12_70 + PIXEL13_60 + if (Diff(w[8], w[4])) + { + PIXEL20_10 + PIXEL21_30 + PIXEL30_80 + PIXEL31_10 + } + else + { + PIXEL20_50 + PIXEL21_0 + PIXEL30_50 + PIXEL31_50 + } + PIXEL22_30 + PIXEL23_61 + PIXEL32_10 + PIXEL33_80 + break; + } + case 10: + case 138: + { + if (Diff(w[4], w[2])) + { + PIXEL00_80 + PIXEL01_10 + PIXEL10_10 + PIXEL11_30 + } + else + { + PIXEL00_50 + PIXEL01_50 + PIXEL10_50 + PIXEL11_0 + } + PIXEL02_10 + PIXEL03_80 + PIXEL12_30 + PIXEL13_61 + PIXEL20_10 + PIXEL21_30 + PIXEL22_70 + PIXEL23_60 + PIXEL30_80 + PIXEL31_61 + PIXEL32_60 + PIXEL33_20 + break; + } + case 66: + { + PIXEL00_80 + PIXEL01_10 + PIXEL02_10 + PIXEL03_80 + PIXEL10_61 + PIXEL11_30 + PIXEL12_30 + PIXEL13_61 + PIXEL20_61 + PIXEL21_30 + PIXEL22_30 + PIXEL23_61 + PIXEL30_80 + PIXEL31_10 + PIXEL32_10 + PIXEL33_80 + break; + } + case 24: + { + PIXEL00_80 + PIXEL01_61 + PIXEL02_61 + PIXEL03_80 + PIXEL10_10 + PIXEL11_30 + PIXEL12_30 + PIXEL13_10 + PIXEL20_10 + PIXEL21_30 + PIXEL22_30 + PIXEL23_10 + PIXEL30_80 + PIXEL31_61 + PIXEL32_61 + PIXEL33_80 + break; + } + case 7: + case 39: + case 135: + { + PIXEL00_81 + PIXEL01_31 + PIXEL02_32 + PIXEL03_82 + PIXEL10_81 + PIXEL11_31 + PIXEL12_32 + PIXEL13_82 + PIXEL20_60 + PIXEL21_70 + PIXEL22_70 + PIXEL23_60 + PIXEL30_20 + PIXEL31_60 + PIXEL32_60 + PIXEL33_20 + break; + } + case 148: + case 149: + case 180: + { + PIXEL00_20 + PIXEL01_60 + PIXEL02_81 + PIXEL03_81 + PIXEL10_60 + PIXEL11_70 + PIXEL12_31 + PIXEL13_31 + PIXEL20_60 + PIXEL21_70 + PIXEL22_32 + PIXEL23_32 + PIXEL30_20 + PIXEL31_60 + PIXEL32_82 + PIXEL33_82 + break; + } + case 224: + case 228: + case 225: + { + PIXEL00_20 + PIXEL01_60 + PIXEL02_60 + PIXEL03_20 + PIXEL10_60 + PIXEL11_70 + PIXEL12_70 + PIXEL13_60 + PIXEL20_82 + PIXEL21_32 + PIXEL22_31 + PIXEL23_81 + PIXEL30_82 + PIXEL31_32 + PIXEL32_31 + PIXEL33_81 + break; + } + case 41: + case 169: + case 45: + { + PIXEL00_82 + PIXEL01_82 + PIXEL02_60 + PIXEL03_20 + PIXEL10_32 + PIXEL11_32 + PIXEL12_70 + PIXEL13_60 + PIXEL20_31 + PIXEL21_31 + PIXEL22_70 + PIXEL23_60 + PIXEL30_81 + PIXEL31_81 + PIXEL32_60 + PIXEL33_20 + break; + } + case 22: + case 54: + { + PIXEL00_80 + PIXEL01_10 + if (Diff(w[2], w[6])) + { + PIXEL02_0 + PIXEL03_0 + PIXEL13_0 + } + else + { + PIXEL02_50 + PIXEL03_50 + PIXEL13_50 + } + PIXEL10_61 + PIXEL11_30 + PIXEL12_0 + PIXEL20_60 + PIXEL21_70 + PIXEL22_30 + PIXEL23_10 + PIXEL30_20 + PIXEL31_60 + PIXEL32_61 + PIXEL33_80 + break; + } + case 208: + case 209: + { + PIXEL00_20 + PIXEL01_60 + PIXEL02_61 + PIXEL03_80 + PIXEL10_60 + PIXEL11_70 + PIXEL12_30 + PIXEL13_10 + PIXEL20_61 + PIXEL21_30 + PIXEL22_0 + if (Diff(w[6], w[8])) + { + PIXEL23_0 + PIXEL32_0 + PIXEL33_0 + } + else + { + PIXEL23_50 + PIXEL32_50 + PIXEL33_50 + } + PIXEL30_80 + PIXEL31_10 + break; + } + case 104: + case 108: + { + PIXEL00_80 + PIXEL01_61 + PIXEL02_60 + PIXEL03_20 + PIXEL10_10 + PIXEL11_30 + PIXEL12_70 + PIXEL13_60 + if (Diff(w[8], w[4])) + { + PIXEL20_0 + PIXEL30_0 + PIXEL31_0 + } + else + { + PIXEL20_50 + PIXEL30_50 + PIXEL31_50 + } + PIXEL21_0 + PIXEL22_30 + PIXEL23_61 + PIXEL32_10 + PIXEL33_80 + break; + } + case 11: + case 139: + { + if (Diff(w[4], w[2])) + { + PIXEL00_0 + PIXEL01_0 + PIXEL10_0 + } + else + { + PIXEL00_50 + PIXEL01_50 + PIXEL10_50 + } + PIXEL02_10 + PIXEL03_80 + PIXEL11_0 + PIXEL12_30 + PIXEL13_61 + PIXEL20_10 + PIXEL21_30 + PIXEL22_70 + PIXEL23_60 + PIXEL30_80 + PIXEL31_61 + PIXEL32_60 + PIXEL33_20 + break; + } + case 19: + case 51: + { + if (Diff(w[2], w[6])) + { + PIXEL00_81 + PIXEL01_31 + PIXEL02_10 + PIXEL03_80 + PIXEL12_30 + PIXEL13_10 + } + else + { + PIXEL00_12 + PIXEL01_14 + PIXEL02_83 + PIXEL03_50 + PIXEL12_70 + PIXEL13_21 + } + PIXEL10_81 + PIXEL11_31 + PIXEL20_60 + PIXEL21_70 + PIXEL22_30 + PIXEL23_10 + PIXEL30_20 + PIXEL31_60 + PIXEL32_61 + PIXEL33_80 + break; + } + case 146: + case 178: + { + PIXEL00_80 + PIXEL01_10 + if (Diff(w[2], w[6])) + { + PIXEL02_10 + PIXEL03_80 + PIXEL12_30 + PIXEL13_10 + PIXEL23_32 + PIXEL33_82 + } + else + { + PIXEL02_21 + PIXEL03_50 + PIXEL12_70 + PIXEL13_83 + PIXEL23_13 + PIXEL33_11 + } + PIXEL10_61 + PIXEL11_30 + PIXEL20_60 + PIXEL21_70 + PIXEL22_32 + PIXEL30_20 + PIXEL31_60 + PIXEL32_82 + break; + } + case 84: + case 85: + { + PIXEL00_20 + PIXEL01_60 + PIXEL02_81 + if (Diff(w[6], w[8])) + { + PIXEL03_81 + PIXEL13_31 + PIXEL22_30 + PIXEL23_10 + PIXEL32_10 + PIXEL33_80 + } + else + { + PIXEL03_12 + PIXEL13_14 + PIXEL22_70 + PIXEL23_83 + PIXEL32_21 + PIXEL33_50 + } + PIXEL10_60 + PIXEL11_70 + PIXEL12_31 + PIXEL20_61 + PIXEL21_30 + PIXEL30_80 + PIXEL31_10 + break; + } + case 112: + case 113: + { + PIXEL00_20 + PIXEL01_60 + PIXEL02_61 + PIXEL03_80 + PIXEL10_60 + PIXEL11_70 + PIXEL12_30 + PIXEL13_10 + PIXEL20_82 + PIXEL21_32 + if (Diff(w[6], w[8])) + { + PIXEL22_30 + PIXEL23_10 + PIXEL30_82 + PIXEL31_32 + PIXEL32_10 + PIXEL33_80 + } + else + { + PIXEL22_70 + PIXEL23_21 + PIXEL30_11 + PIXEL31_13 + PIXEL32_83 + PIXEL33_50 + } + break; + } + case 200: + case 204: + { + PIXEL00_80 + PIXEL01_61 + PIXEL02_60 + PIXEL03_20 + PIXEL10_10 + PIXEL11_30 + PIXEL12_70 + PIXEL13_60 + if (Diff(w[8], w[4])) + { + PIXEL20_10 + PIXEL21_30 + PIXEL30_80 + PIXEL31_10 + PIXEL32_31 + PIXEL33_81 + } + else + { + PIXEL20_21 + PIXEL21_70 + PIXEL30_50 + PIXEL31_83 + PIXEL32_14 + PIXEL33_12 + } + PIXEL22_31 + PIXEL23_81 + break; + } + case 73: + case 77: + { + if (Diff(w[8], w[4])) + { + PIXEL00_82 + PIXEL10_32 + PIXEL20_10 + PIXEL21_30 + PIXEL30_80 + PIXEL31_10 + } + else + { + PIXEL00_11 + PIXEL10_13 + PIXEL20_83 + PIXEL21_70 + PIXEL30_50 + PIXEL31_21 + } + PIXEL01_82 + PIXEL02_60 + PIXEL03_20 + PIXEL11_32 + PIXEL12_70 + PIXEL13_60 + PIXEL22_30 + PIXEL23_61 + PIXEL32_10 + PIXEL33_80 + break; + } + case 42: + case 170: + { + if (Diff(w[4], w[2])) + { + PIXEL00_80 + PIXEL01_10 + PIXEL10_10 + PIXEL11_30 + PIXEL20_31 + PIXEL30_81 + } + else + { + PIXEL00_50 + PIXEL01_21 + PIXEL10_83 + PIXEL11_70 + PIXEL20_14 + PIXEL30_12 + } + PIXEL02_10 + PIXEL03_80 + PIXEL12_30 + PIXEL13_61 + PIXEL21_31 + PIXEL22_70 + PIXEL23_60 + PIXEL31_81 + PIXEL32_60 + PIXEL33_20 + break; + } + case 14: + case 142: + { + if (Diff(w[4], w[2])) + { + PIXEL00_80 + PIXEL01_10 + PIXEL02_32 + PIXEL03_82 + PIXEL10_10 + PIXEL11_30 + } + else + { + PIXEL00_50 + PIXEL01_83 + PIXEL02_13 + PIXEL03_11 + PIXEL10_21 + PIXEL11_70 + } + PIXEL12_32 + PIXEL13_82 + PIXEL20_10 + PIXEL21_30 + PIXEL22_70 + PIXEL23_60 + PIXEL30_80 + PIXEL31_61 + PIXEL32_60 + PIXEL33_20 + break; + } + case 67: + { + PIXEL00_81 + PIXEL01_31 + PIXEL02_10 + PIXEL03_80 + PIXEL10_81 + PIXEL11_31 + PIXEL12_30 + PIXEL13_61 + PIXEL20_61 + PIXEL21_30 + PIXEL22_30 + PIXEL23_61 + PIXEL30_80 + PIXEL31_10 + PIXEL32_10 + PIXEL33_80 + break; + } + case 70: + { + PIXEL00_80 + PIXEL01_10 + PIXEL02_32 + PIXEL03_82 + PIXEL10_61 + PIXEL11_30 + PIXEL12_32 + PIXEL13_82 + PIXEL20_61 + PIXEL21_30 + PIXEL22_30 + PIXEL23_61 + PIXEL30_80 + PIXEL31_10 + PIXEL32_10 + PIXEL33_80 + break; + } + case 28: + { + PIXEL00_80 + PIXEL01_61 + PIXEL02_81 + PIXEL03_81 + PIXEL10_10 + PIXEL11_30 + PIXEL12_31 + PIXEL13_31 + PIXEL20_10 + PIXEL21_30 + PIXEL22_30 + PIXEL23_10 + PIXEL30_80 + PIXEL31_61 + PIXEL32_61 + PIXEL33_80 + break; + } + case 152: + { + PIXEL00_80 + PIXEL01_61 + PIXEL02_61 + PIXEL03_80 + PIXEL10_10 + PIXEL11_30 + PIXEL12_30 + PIXEL13_10 + PIXEL20_10 + PIXEL21_30 + PIXEL22_32 + PIXEL23_32 + PIXEL30_80 + PIXEL31_61 + PIXEL32_82 + PIXEL33_82 + break; + } + case 194: + { + PIXEL00_80 + PIXEL01_10 + PIXEL02_10 + PIXEL03_80 + PIXEL10_61 + PIXEL11_30 + PIXEL12_30 + PIXEL13_61 + PIXEL20_61 + PIXEL21_30 + PIXEL22_31 + PIXEL23_81 + PIXEL30_80 + PIXEL31_10 + PIXEL32_31 + PIXEL33_81 + break; + } + case 98: + { + PIXEL00_80 + PIXEL01_10 + PIXEL02_10 + PIXEL03_80 + PIXEL10_61 + PIXEL11_30 + PIXEL12_30 + PIXEL13_61 + PIXEL20_82 + PIXEL21_32 + PIXEL22_30 + PIXEL23_61 + PIXEL30_82 + PIXEL31_32 + PIXEL32_10 + PIXEL33_80 + break; + } + case 56: + { + PIXEL00_80 + PIXEL01_61 + PIXEL02_61 + PIXEL03_80 + PIXEL10_10 + PIXEL11_30 + PIXEL12_30 + PIXEL13_10 + PIXEL20_31 + PIXEL21_31 + PIXEL22_30 + PIXEL23_10 + PIXEL30_81 + PIXEL31_81 + PIXEL32_61 + PIXEL33_80 + break; + } + case 25: + { + PIXEL00_82 + PIXEL01_82 + PIXEL02_61 + PIXEL03_80 + PIXEL10_32 + PIXEL11_32 + PIXEL12_30 + PIXEL13_10 + PIXEL20_10 + PIXEL21_30 + PIXEL22_30 + PIXEL23_10 + PIXEL30_80 + PIXEL31_61 + PIXEL32_61 + PIXEL33_80 + break; + } + case 26: + case 31: + { + if (Diff(w[4], w[2])) + { + PIXEL00_0 + PIXEL01_0 + PIXEL10_0 + } + else + { + PIXEL00_50 + PIXEL01_50 + PIXEL10_50 + } + if (Diff(w[2], w[6])) + { + PIXEL02_0 + PIXEL03_0 + PIXEL13_0 + } + else + { + PIXEL02_50 + PIXEL03_50 + PIXEL13_50 + } + PIXEL11_0 + PIXEL12_0 + PIXEL20_10 + PIXEL21_30 + PIXEL22_30 + PIXEL23_10 + PIXEL30_80 + PIXEL31_61 + PIXEL32_61 + PIXEL33_80 + break; + } + case 82: + case 214: + { + PIXEL00_80 + PIXEL01_10 + if (Diff(w[2], w[6])) + { + PIXEL02_0 + PIXEL03_0 + PIXEL13_0 + } + else + { + PIXEL02_50 + PIXEL03_50 + PIXEL13_50 + } + PIXEL10_61 + PIXEL11_30 + PIXEL12_0 + PIXEL20_61 + PIXEL21_30 + PIXEL22_0 + if (Diff(w[6], w[8])) + { + PIXEL23_0 + PIXEL32_0 + PIXEL33_0 + } + else + { + PIXEL23_50 + PIXEL32_50 + PIXEL33_50 + } + PIXEL30_80 + PIXEL31_10 + break; + } + case 88: + case 248: + { + PIXEL00_80 + PIXEL01_61 + PIXEL02_61 + PIXEL03_80 + PIXEL10_10 + PIXEL11_30 + PIXEL12_30 + PIXEL13_10 + if (Diff(w[8], w[4])) + { + PIXEL20_0 + PIXEL30_0 + PIXEL31_0 + } + else + { + PIXEL20_50 + PIXEL30_50 + PIXEL31_50 + } + PIXEL21_0 + PIXEL22_0 + if (Diff(w[6], w[8])) + { + PIXEL23_0 + PIXEL32_0 + PIXEL33_0 + } + else + { + PIXEL23_50 + PIXEL32_50 + PIXEL33_50 + } + break; + } + case 74: + case 107: + { + if (Diff(w[4], w[2])) + { + PIXEL00_0 + PIXEL01_0 + PIXEL10_0 + } + else + { + PIXEL00_50 + PIXEL01_50 + PIXEL10_50 + } + PIXEL02_10 + PIXEL03_80 + PIXEL11_0 + PIXEL12_30 + PIXEL13_61 + if (Diff(w[8], w[4])) + { + PIXEL20_0 + PIXEL30_0 + PIXEL31_0 + } + else + { + PIXEL20_50 + PIXEL30_50 + PIXEL31_50 + } + PIXEL21_0 + PIXEL22_30 + PIXEL23_61 + PIXEL32_10 + PIXEL33_80 + break; + } + case 27: + { + if (Diff(w[4], w[2])) + { + PIXEL00_0 + PIXEL01_0 + PIXEL10_0 + } + else + { + PIXEL00_50 + PIXEL01_50 + PIXEL10_50 + } + PIXEL02_10 + PIXEL03_80 + PIXEL11_0 + PIXEL12_30 + PIXEL13_10 + PIXEL20_10 + PIXEL21_30 + PIXEL22_30 + PIXEL23_10 + PIXEL30_80 + PIXEL31_61 + PIXEL32_61 + PIXEL33_80 + break; + } + case 86: + { + PIXEL00_80 + PIXEL01_10 + if (Diff(w[2], w[6])) + { + PIXEL02_0 + PIXEL03_0 + PIXEL13_0 + } + else + { + PIXEL02_50 + PIXEL03_50 + PIXEL13_50 + } + PIXEL10_61 + PIXEL11_30 + PIXEL12_0 + PIXEL20_61 + PIXEL21_30 + PIXEL22_30 + PIXEL23_10 + PIXEL30_80 + PIXEL31_10 + PIXEL32_10 + PIXEL33_80 + break; + } + case 216: + { + PIXEL00_80 + PIXEL01_61 + PIXEL02_61 + PIXEL03_80 + PIXEL10_10 + PIXEL11_30 + PIXEL12_30 + PIXEL13_10 + PIXEL20_10 + PIXEL21_30 + PIXEL22_0 + if (Diff(w[6], w[8])) + { + PIXEL23_0 + PIXEL32_0 + PIXEL33_0 + } + else + { + PIXEL23_50 + PIXEL32_50 + PIXEL33_50 + } + PIXEL30_80 + PIXEL31_10 + break; + } + case 106: + { + PIXEL00_80 + PIXEL01_10 + PIXEL02_10 + PIXEL03_80 + PIXEL10_10 + PIXEL11_30 + PIXEL12_30 + PIXEL13_61 + if (Diff(w[8], w[4])) + { + PIXEL20_0 + PIXEL30_0 + PIXEL31_0 + } + else + { + PIXEL20_50 + PIXEL30_50 + PIXEL31_50 + } + PIXEL21_0 + PIXEL22_30 + PIXEL23_61 + PIXEL32_10 + PIXEL33_80 + break; + } + case 30: + { + PIXEL00_80 + PIXEL01_10 + if (Diff(w[2], w[6])) + { + PIXEL02_0 + PIXEL03_0 + PIXEL13_0 + } + else + { + PIXEL02_50 + PIXEL03_50 + PIXEL13_50 + } + PIXEL10_10 + PIXEL11_30 + PIXEL12_0 + PIXEL20_10 + PIXEL21_30 + PIXEL22_30 + PIXEL23_10 + PIXEL30_80 + PIXEL31_61 + PIXEL32_61 + PIXEL33_80 + break; + } + case 210: + { + PIXEL00_80 + PIXEL01_10 + PIXEL02_10 + PIXEL03_80 + PIXEL10_61 + PIXEL11_30 + PIXEL12_30 + PIXEL13_10 + PIXEL20_61 + PIXEL21_30 + PIXEL22_0 + if (Diff(w[6], w[8])) + { + PIXEL23_0 + PIXEL32_0 + PIXEL33_0 + } + else + { + PIXEL23_50 + PIXEL32_50 + PIXEL33_50 + } + PIXEL30_80 + PIXEL31_10 + break; + } + case 120: + { + PIXEL00_80 + PIXEL01_61 + PIXEL02_61 + PIXEL03_80 + PIXEL10_10 + PIXEL11_30 + PIXEL12_30 + PIXEL13_10 + if (Diff(w[8], w[4])) + { + PIXEL20_0 + PIXEL30_0 + PIXEL31_0 + } + else + { + PIXEL20_50 + PIXEL30_50 + PIXEL31_50 + } + PIXEL21_0 + PIXEL22_30 + PIXEL23_10 + PIXEL32_10 + PIXEL33_80 + break; + } + case 75: + { + if (Diff(w[4], w[2])) + { + PIXEL00_0 + PIXEL01_0 + PIXEL10_0 + } + else + { + PIXEL00_50 + PIXEL01_50 + PIXEL10_50 + } + PIXEL02_10 + PIXEL03_80 + PIXEL11_0 + PIXEL12_30 + PIXEL13_61 + PIXEL20_10 + PIXEL21_30 + PIXEL22_30 + PIXEL23_61 + PIXEL30_80 + PIXEL31_10 + PIXEL32_10 + PIXEL33_80 + break; + } + case 29: + { + PIXEL00_82 + PIXEL01_82 + PIXEL02_81 + PIXEL03_81 + PIXEL10_32 + PIXEL11_32 + PIXEL12_31 + PIXEL13_31 + PIXEL20_10 + PIXEL21_30 + PIXEL22_30 + PIXEL23_10 + PIXEL30_80 + PIXEL31_61 + PIXEL32_61 + PIXEL33_80 + break; + } + case 198: + { + PIXEL00_80 + PIXEL01_10 + PIXEL02_32 + PIXEL03_82 + PIXEL10_61 + PIXEL11_30 + PIXEL12_32 + PIXEL13_82 + PIXEL20_61 + PIXEL21_30 + PIXEL22_31 + PIXEL23_81 + PIXEL30_80 + PIXEL31_10 + PIXEL32_31 + PIXEL33_81 + break; + } + case 184: + { + PIXEL00_80 + PIXEL01_61 + PIXEL02_61 + PIXEL03_80 + PIXEL10_10 + PIXEL11_30 + PIXEL12_30 + PIXEL13_10 + PIXEL20_31 + PIXEL21_31 + PIXEL22_32 + PIXEL23_32 + PIXEL30_81 + PIXEL31_81 + PIXEL32_82 + PIXEL33_82 + break; + } + case 99: + { + PIXEL00_81 + PIXEL01_31 + PIXEL02_10 + PIXEL03_80 + PIXEL10_81 + PIXEL11_31 + PIXEL12_30 + PIXEL13_61 + PIXEL20_82 + PIXEL21_32 + PIXEL22_30 + PIXEL23_61 + PIXEL30_82 + PIXEL31_32 + PIXEL32_10 + PIXEL33_80 + break; + } + case 57: + { + PIXEL00_82 + PIXEL01_82 + PIXEL02_61 + PIXEL03_80 + PIXEL10_32 + PIXEL11_32 + PIXEL12_30 + PIXEL13_10 + PIXEL20_31 + PIXEL21_31 + PIXEL22_30 + PIXEL23_10 + PIXEL30_81 + PIXEL31_81 + PIXEL32_61 + PIXEL33_80 + break; + } + case 71: + { + PIXEL00_81 + PIXEL01_31 + PIXEL02_32 + PIXEL03_82 + PIXEL10_81 + PIXEL11_31 + PIXEL12_32 + PIXEL13_82 + PIXEL20_61 + PIXEL21_30 + PIXEL22_30 + PIXEL23_61 + PIXEL30_80 + PIXEL31_10 + PIXEL32_10 + PIXEL33_80 + break; + } + case 156: + { + PIXEL00_80 + PIXEL01_61 + PIXEL02_81 + PIXEL03_81 + PIXEL10_10 + PIXEL11_30 + PIXEL12_31 + PIXEL13_31 + PIXEL20_10 + PIXEL21_30 + PIXEL22_32 + PIXEL23_32 + PIXEL30_80 + PIXEL31_61 + PIXEL32_82 + PIXEL33_82 + break; + } + case 226: + { + PIXEL00_80 + PIXEL01_10 + PIXEL02_10 + PIXEL03_80 + PIXEL10_61 + PIXEL11_30 + PIXEL12_30 + PIXEL13_61 + PIXEL20_82 + PIXEL21_32 + PIXEL22_31 + PIXEL23_81 + PIXEL30_82 + PIXEL31_32 + PIXEL32_31 + PIXEL33_81 + break; + } + case 60: + { + PIXEL00_80 + PIXEL01_61 + PIXEL02_81 + PIXEL03_81 + PIXEL10_10 + PIXEL11_30 + PIXEL12_31 + PIXEL13_31 + PIXEL20_31 + PIXEL21_31 + PIXEL22_30 + PIXEL23_10 + PIXEL30_81 + PIXEL31_81 + PIXEL32_61 + PIXEL33_80 + break; + } + case 195: + { + PIXEL00_81 + PIXEL01_31 + PIXEL02_10 + PIXEL03_80 + PIXEL10_81 + PIXEL11_31 + PIXEL12_30 + PIXEL13_61 + PIXEL20_61 + PIXEL21_30 + PIXEL22_31 + PIXEL23_81 + PIXEL30_80 + PIXEL31_10 + PIXEL32_31 + PIXEL33_81 + break; + } + case 102: + { + PIXEL00_80 + PIXEL01_10 + PIXEL02_32 + PIXEL03_82 + PIXEL10_61 + PIXEL11_30 + PIXEL12_32 + PIXEL13_82 + PIXEL20_82 + PIXEL21_32 + PIXEL22_30 + PIXEL23_61 + PIXEL30_82 + PIXEL31_32 + PIXEL32_10 + PIXEL33_80 + break; + } + case 153: + { + PIXEL00_82 + PIXEL01_82 + PIXEL02_61 + PIXEL03_80 + PIXEL10_32 + PIXEL11_32 + PIXEL12_30 + PIXEL13_10 + PIXEL20_10 + PIXEL21_30 + PIXEL22_32 + PIXEL23_32 + PIXEL30_80 + PIXEL31_61 + PIXEL32_82 + PIXEL33_82 + break; + } + case 58: + { + if (Diff(w[4], w[2])) + { + PIXEL00_80 + PIXEL01_10 + PIXEL10_10 + PIXEL11_30 + } + else + { + PIXEL00_20 + PIXEL01_12 + PIXEL10_11 + PIXEL11_0 + } + if (Diff(w[2], w[6])) + { + PIXEL02_10 + PIXEL03_80 + PIXEL12_30 + PIXEL13_10 + } + else + { + PIXEL02_11 + PIXEL03_20 + PIXEL12_0 + PIXEL13_12 + } + PIXEL20_31 + PIXEL21_31 + PIXEL22_30 + PIXEL23_10 + PIXEL30_81 + PIXEL31_81 + PIXEL32_61 + PIXEL33_80 + break; + } + case 83: + { + PIXEL00_81 + PIXEL01_31 + if (Diff(w[2], w[6])) + { + PIXEL02_10 + PIXEL03_80 + PIXEL12_30 + PIXEL13_10 + } + else + { + PIXEL02_11 + PIXEL03_20 + PIXEL12_0 + PIXEL13_12 + } + PIXEL10_81 + PIXEL11_31 + PIXEL20_61 + PIXEL21_30 + if (Diff(w[6], w[8])) + { + PIXEL22_30 + PIXEL23_10 + PIXEL32_10 + PIXEL33_80 + } + else + { + PIXEL22_0 + PIXEL23_11 + PIXEL32_12 + PIXEL33_20 + } + PIXEL30_80 + PIXEL31_10 + break; + } + case 92: + { + PIXEL00_80 + PIXEL01_61 + PIXEL02_81 + PIXEL03_81 + PIXEL10_10 + PIXEL11_30 + PIXEL12_31 + PIXEL13_31 + if (Diff(w[8], w[4])) + { + PIXEL20_10 + PIXEL21_30 + PIXEL30_80 + PIXEL31_10 + } + else + { + PIXEL20_12 + PIXEL21_0 + PIXEL30_20 + PIXEL31_11 + } + if (Diff(w[6], w[8])) + { + PIXEL22_30 + PIXEL23_10 + PIXEL32_10 + PIXEL33_80 + } + else + { + PIXEL22_0 + PIXEL23_11 + PIXEL32_12 + PIXEL33_20 + } + break; + } + case 202: + { + if (Diff(w[4], w[2])) + { + PIXEL00_80 + PIXEL01_10 + PIXEL10_10 + PIXEL11_30 + } + else + { + PIXEL00_20 + PIXEL01_12 + PIXEL10_11 + PIXEL11_0 + } + PIXEL02_10 + PIXEL03_80 + PIXEL12_30 + PIXEL13_61 + if (Diff(w[8], w[4])) + { + PIXEL20_10 + PIXEL21_30 + PIXEL30_80 + PIXEL31_10 + } + else + { + PIXEL20_12 + PIXEL21_0 + PIXEL30_20 + PIXEL31_11 + } + PIXEL22_31 + PIXEL23_81 + PIXEL32_31 + PIXEL33_81 + break; + } + case 78: + { + if (Diff(w[4], w[2])) + { + PIXEL00_80 + PIXEL01_10 + PIXEL10_10 + PIXEL11_30 + } + else + { + PIXEL00_20 + PIXEL01_12 + PIXEL10_11 + PIXEL11_0 + } + PIXEL02_32 + PIXEL03_82 + PIXEL12_32 + PIXEL13_82 + if (Diff(w[8], w[4])) + { + PIXEL20_10 + PIXEL21_30 + PIXEL30_80 + PIXEL31_10 + } + else + { + PIXEL20_12 + PIXEL21_0 + PIXEL30_20 + PIXEL31_11 + } + PIXEL22_30 + PIXEL23_61 + PIXEL32_10 + PIXEL33_80 + break; + } + case 154: + { + if (Diff(w[4], w[2])) + { + PIXEL00_80 + PIXEL01_10 + PIXEL10_10 + PIXEL11_30 + } + else + { + PIXEL00_20 + PIXEL01_12 + PIXEL10_11 + PIXEL11_0 + } + if (Diff(w[2], w[6])) + { + PIXEL02_10 + PIXEL03_80 + PIXEL12_30 + PIXEL13_10 + } + else + { + PIXEL02_11 + PIXEL03_20 + PIXEL12_0 + PIXEL13_12 + } + PIXEL20_10 + PIXEL21_30 + PIXEL22_32 + PIXEL23_32 + PIXEL30_80 + PIXEL31_61 + PIXEL32_82 + PIXEL33_82 + break; + } + case 114: + { + PIXEL00_80 + PIXEL01_10 + if (Diff(w[2], w[6])) + { + PIXEL02_10 + PIXEL03_80 + PIXEL12_30 + PIXEL13_10 + } + else + { + PIXEL02_11 + PIXEL03_20 + PIXEL12_0 + PIXEL13_12 + } + PIXEL10_61 + PIXEL11_30 + PIXEL20_82 + PIXEL21_32 + if (Diff(w[6], w[8])) + { + PIXEL22_30 + PIXEL23_10 + PIXEL32_10 + PIXEL33_80 + } + else + { + PIXEL22_0 + PIXEL23_11 + PIXEL32_12 + PIXEL33_20 + } + PIXEL30_82 + PIXEL31_32 + break; + } + case 89: + { + PIXEL00_82 + PIXEL01_82 + PIXEL02_61 + PIXEL03_80 + PIXEL10_32 + PIXEL11_32 + PIXEL12_30 + PIXEL13_10 + if (Diff(w[8], w[4])) + { + PIXEL20_10 + PIXEL21_30 + PIXEL30_80 + PIXEL31_10 + } + else + { + PIXEL20_12 + PIXEL21_0 + PIXEL30_20 + PIXEL31_11 + } + if (Diff(w[6], w[8])) + { + PIXEL22_30 + PIXEL23_10 + PIXEL32_10 + PIXEL33_80 + } + else + { + PIXEL22_0 + PIXEL23_11 + PIXEL32_12 + PIXEL33_20 + } + break; + } + case 90: + { + if (Diff(w[4], w[2])) + { + PIXEL00_80 + PIXEL01_10 + PIXEL10_10 + PIXEL11_30 + } + else + { + PIXEL00_20 + PIXEL01_12 + PIXEL10_11 + PIXEL11_0 + } + if (Diff(w[2], w[6])) + { + PIXEL02_10 + PIXEL03_80 + PIXEL12_30 + PIXEL13_10 + } + else + { + PIXEL02_11 + PIXEL03_20 + PIXEL12_0 + PIXEL13_12 + } + if (Diff(w[8], w[4])) + { + PIXEL20_10 + PIXEL21_30 + PIXEL30_80 + PIXEL31_10 + } + else + { + PIXEL20_12 + PIXEL21_0 + PIXEL30_20 + PIXEL31_11 + } + if (Diff(w[6], w[8])) + { + PIXEL22_30 + PIXEL23_10 + PIXEL32_10 + PIXEL33_80 + } + else + { + PIXEL22_0 + PIXEL23_11 + PIXEL32_12 + PIXEL33_20 + } + break; + } + case 55: + case 23: + { + if (Diff(w[2], w[6])) + { + PIXEL00_81 + PIXEL01_31 + PIXEL02_0 + PIXEL03_0 + PIXEL12_0 + PIXEL13_0 + } + else + { + PIXEL00_12 + PIXEL01_14 + PIXEL02_83 + PIXEL03_50 + PIXEL12_70 + PIXEL13_21 + } + PIXEL10_81 + PIXEL11_31 + PIXEL20_60 + PIXEL21_70 + PIXEL22_30 + PIXEL23_10 + PIXEL30_20 + PIXEL31_60 + PIXEL32_61 + PIXEL33_80 + break; + } + case 182: + case 150: + { + PIXEL00_80 + PIXEL01_10 + if (Diff(w[2], w[6])) + { + PIXEL02_0 + PIXEL03_0 + PIXEL12_0 + PIXEL13_0 + PIXEL23_32 + PIXEL33_82 + } + else + { + PIXEL02_21 + PIXEL03_50 + PIXEL12_70 + PIXEL13_83 + PIXEL23_13 + PIXEL33_11 + } + PIXEL10_61 + PIXEL11_30 + PIXEL20_60 + PIXEL21_70 + PIXEL22_32 + PIXEL30_20 + PIXEL31_60 + PIXEL32_82 + break; + } + case 213: + case 212: + { + PIXEL00_20 + PIXEL01_60 + PIXEL02_81 + if (Diff(w[6], w[8])) + { + PIXEL03_81 + PIXEL13_31 + PIXEL22_0 + PIXEL23_0 + PIXEL32_0 + PIXEL33_0 + } + else + { + PIXEL03_12 + PIXEL13_14 + PIXEL22_70 + PIXEL23_83 + PIXEL32_21 + PIXEL33_50 + } + PIXEL10_60 + PIXEL11_70 + PIXEL12_31 + PIXEL20_61 + PIXEL21_30 + PIXEL30_80 + PIXEL31_10 + break; + } + case 241: + case 240: + { + PIXEL00_20 + PIXEL01_60 + PIXEL02_61 + PIXEL03_80 + PIXEL10_60 + PIXEL11_70 + PIXEL12_30 + PIXEL13_10 + PIXEL20_82 + PIXEL21_32 + if (Diff(w[6], w[8])) + { + PIXEL22_0 + PIXEL23_0 + PIXEL30_82 + PIXEL31_32 + PIXEL32_0 + PIXEL33_0 + } + else + { + PIXEL22_70 + PIXEL23_21 + PIXEL30_11 + PIXEL31_13 + PIXEL32_83 + PIXEL33_50 + } + break; + } + case 236: + case 232: + { + PIXEL00_80 + PIXEL01_61 + PIXEL02_60 + PIXEL03_20 + PIXEL10_10 + PIXEL11_30 + PIXEL12_70 + PIXEL13_60 + if (Diff(w[8], w[4])) + { + PIXEL20_0 + PIXEL21_0 + PIXEL30_0 + PIXEL31_0 + PIXEL32_31 + PIXEL33_81 + } + else + { + PIXEL20_21 + PIXEL21_70 + PIXEL30_50 + PIXEL31_83 + PIXEL32_14 + PIXEL33_12 + } + PIXEL22_31 + PIXEL23_81 + break; + } + case 109: + case 105: + { + if (Diff(w[8], w[4])) + { + PIXEL00_82 + PIXEL10_32 + PIXEL20_0 + PIXEL21_0 + PIXEL30_0 + PIXEL31_0 + } + else + { + PIXEL00_11 + PIXEL10_13 + PIXEL20_83 + PIXEL21_70 + PIXEL30_50 + PIXEL31_21 + } + PIXEL01_82 + PIXEL02_60 + PIXEL03_20 + PIXEL11_32 + PIXEL12_70 + PIXEL13_60 + PIXEL22_30 + PIXEL23_61 + PIXEL32_10 + PIXEL33_80 + break; + } + case 171: + case 43: + { + if (Diff(w[4], w[2])) + { + PIXEL00_0 + PIXEL01_0 + PIXEL10_0 + PIXEL11_0 + PIXEL20_31 + PIXEL30_81 + } + else + { + PIXEL00_50 + PIXEL01_21 + PIXEL10_83 + PIXEL11_70 + PIXEL20_14 + PIXEL30_12 + } + PIXEL02_10 + PIXEL03_80 + PIXEL12_30 + PIXEL13_61 + PIXEL21_31 + PIXEL22_70 + PIXEL23_60 + PIXEL31_81 + PIXEL32_60 + PIXEL33_20 + break; + } + case 143: + case 15: + { + if (Diff(w[4], w[2])) + { + PIXEL00_0 + PIXEL01_0 + PIXEL02_32 + PIXEL03_82 + PIXEL10_0 + PIXEL11_0 + } + else + { + PIXEL00_50 + PIXEL01_83 + PIXEL02_13 + PIXEL03_11 + PIXEL10_21 + PIXEL11_70 + } + PIXEL12_32 + PIXEL13_82 + PIXEL20_10 + PIXEL21_30 + PIXEL22_70 + PIXEL23_60 + PIXEL30_80 + PIXEL31_61 + PIXEL32_60 + PIXEL33_20 + break; + } + case 124: + { + PIXEL00_80 + PIXEL01_61 + PIXEL02_81 + PIXEL03_81 + PIXEL10_10 + PIXEL11_30 + PIXEL12_31 + PIXEL13_31 + if (Diff(w[8], w[4])) + { + PIXEL20_0 + PIXEL30_0 + PIXEL31_0 + } + else + { + PIXEL20_50 + PIXEL30_50 + PIXEL31_50 + } + PIXEL21_0 + PIXEL22_30 + PIXEL23_10 + PIXEL32_10 + PIXEL33_80 + break; + } + case 203: + { + if (Diff(w[4], w[2])) + { + PIXEL00_0 + PIXEL01_0 + PIXEL10_0 + } + else + { + PIXEL00_50 + PIXEL01_50 + PIXEL10_50 + } + PIXEL02_10 + PIXEL03_80 + PIXEL11_0 + PIXEL12_30 + PIXEL13_61 + PIXEL20_10 + PIXEL21_30 + PIXEL22_31 + PIXEL23_81 + PIXEL30_80 + PIXEL31_10 + PIXEL32_31 + PIXEL33_81 + break; + } + case 62: + { + PIXEL00_80 + PIXEL01_10 + if (Diff(w[2], w[6])) + { + PIXEL02_0 + PIXEL03_0 + PIXEL13_0 + } + else + { + PIXEL02_50 + PIXEL03_50 + PIXEL13_50 + } + PIXEL10_10 + PIXEL11_30 + PIXEL12_0 + PIXEL20_31 + PIXEL21_31 + PIXEL22_30 + PIXEL23_10 + PIXEL30_81 + PIXEL31_81 + PIXEL32_61 + PIXEL33_80 + break; + } + case 211: + { + PIXEL00_81 + PIXEL01_31 + PIXEL02_10 + PIXEL03_80 + PIXEL10_81 + PIXEL11_31 + PIXEL12_30 + PIXEL13_10 + PIXEL20_61 + PIXEL21_30 + PIXEL22_0 + if (Diff(w[6], w[8])) + { + PIXEL23_0 + PIXEL32_0 + PIXEL33_0 + } + else + { + PIXEL23_50 + PIXEL32_50 + PIXEL33_50 + } + PIXEL30_80 + PIXEL31_10 + break; + } + case 118: + { + PIXEL00_80 + PIXEL01_10 + if (Diff(w[2], w[6])) + { + PIXEL02_0 + PIXEL03_0 + PIXEL13_0 + } + else + { + PIXEL02_50 + PIXEL03_50 + PIXEL13_50 + } + PIXEL10_61 + PIXEL11_30 + PIXEL12_0 + PIXEL20_82 + PIXEL21_32 + PIXEL22_30 + PIXEL23_10 + PIXEL30_82 + PIXEL31_32 + PIXEL32_10 + PIXEL33_80 + break; + } + case 217: + { + PIXEL00_82 + PIXEL01_82 + PIXEL02_61 + PIXEL03_80 + PIXEL10_32 + PIXEL11_32 + PIXEL12_30 + PIXEL13_10 + PIXEL20_10 + PIXEL21_30 + PIXEL22_0 + if (Diff(w[6], w[8])) + { + PIXEL23_0 + PIXEL32_0 + PIXEL33_0 + } + else + { + PIXEL23_50 + PIXEL32_50 + PIXEL33_50 + } + PIXEL30_80 + PIXEL31_10 + break; + } + case 110: + { + PIXEL00_80 + PIXEL01_10 + PIXEL02_32 + PIXEL03_82 + PIXEL10_10 + PIXEL11_30 + PIXEL12_32 + PIXEL13_82 + if (Diff(w[8], w[4])) + { + PIXEL20_0 + PIXEL30_0 + PIXEL31_0 + } + else + { + PIXEL20_50 + PIXEL30_50 + PIXEL31_50 + } + PIXEL21_0 + PIXEL22_30 + PIXEL23_61 + PIXEL32_10 + PIXEL33_80 + break; + } + case 155: + { + if (Diff(w[4], w[2])) + { + PIXEL00_0 + PIXEL01_0 + PIXEL10_0 + } + else + { + PIXEL00_50 + PIXEL01_50 + PIXEL10_50 + } + PIXEL02_10 + PIXEL03_80 + PIXEL11_0 + PIXEL12_30 + PIXEL13_10 + PIXEL20_10 + PIXEL21_30 + PIXEL22_32 + PIXEL23_32 + PIXEL30_80 + PIXEL31_61 + PIXEL32_82 + PIXEL33_82 + break; + } + case 188: + { + PIXEL00_80 + PIXEL01_61 + PIXEL02_81 + PIXEL03_81 + PIXEL10_10 + PIXEL11_30 + PIXEL12_31 + PIXEL13_31 + PIXEL20_31 + PIXEL21_31 + PIXEL22_32 + PIXEL23_32 + PIXEL30_81 + PIXEL31_81 + PIXEL32_82 + PIXEL33_82 + break; + } + case 185: + { + PIXEL00_82 + PIXEL01_82 + PIXEL02_61 + PIXEL03_80 + PIXEL10_32 + PIXEL11_32 + PIXEL12_30 + PIXEL13_10 + PIXEL20_31 + PIXEL21_31 + PIXEL22_32 + PIXEL23_32 + PIXEL30_81 + PIXEL31_81 + PIXEL32_82 + PIXEL33_82 + break; + } + case 61: + { + PIXEL00_82 + PIXEL01_82 + PIXEL02_81 + PIXEL03_81 + PIXEL10_32 + PIXEL11_32 + PIXEL12_31 + PIXEL13_31 + PIXEL20_31 + PIXEL21_31 + PIXEL22_30 + PIXEL23_10 + PIXEL30_81 + PIXEL31_81 + PIXEL32_61 + PIXEL33_80 + break; + } + case 157: + { + PIXEL00_82 + PIXEL01_82 + PIXEL02_81 + PIXEL03_81 + PIXEL10_32 + PIXEL11_32 + PIXEL12_31 + PIXEL13_31 + PIXEL20_10 + PIXEL21_30 + PIXEL22_32 + PIXEL23_32 + PIXEL30_80 + PIXEL31_61 + PIXEL32_82 + PIXEL33_82 + break; + } + case 103: + { + PIXEL00_81 + PIXEL01_31 + PIXEL02_32 + PIXEL03_82 + PIXEL10_81 + PIXEL11_31 + PIXEL12_32 + PIXEL13_82 + PIXEL20_82 + PIXEL21_32 + PIXEL22_30 + PIXEL23_61 + PIXEL30_82 + PIXEL31_32 + PIXEL32_10 + PIXEL33_80 + break; + } + case 227: + { + PIXEL00_81 + PIXEL01_31 + PIXEL02_10 + PIXEL03_80 + PIXEL10_81 + PIXEL11_31 + PIXEL12_30 + PIXEL13_61 + PIXEL20_82 + PIXEL21_32 + PIXEL22_31 + PIXEL23_81 + PIXEL30_82 + PIXEL31_32 + PIXEL32_31 + PIXEL33_81 + break; + } + case 230: + { + PIXEL00_80 + PIXEL01_10 + PIXEL02_32 + PIXEL03_82 + PIXEL10_61 + PIXEL11_30 + PIXEL12_32 + PIXEL13_82 + PIXEL20_82 + PIXEL21_32 + PIXEL22_31 + PIXEL23_81 + PIXEL30_82 + PIXEL31_32 + PIXEL32_31 + PIXEL33_81 + break; + } + case 199: + { + PIXEL00_81 + PIXEL01_31 + PIXEL02_32 + PIXEL03_82 + PIXEL10_81 + PIXEL11_31 + PIXEL12_32 + PIXEL13_82 + PIXEL20_61 + PIXEL21_30 + PIXEL22_31 + PIXEL23_81 + PIXEL30_80 + PIXEL31_10 + PIXEL32_31 + PIXEL33_81 + break; + } + case 220: + { + PIXEL00_80 + PIXEL01_61 + PIXEL02_81 + PIXEL03_81 + PIXEL10_10 + PIXEL11_30 + PIXEL12_31 + PIXEL13_31 + if (Diff(w[8], w[4])) + { + PIXEL20_10 + PIXEL21_30 + PIXEL30_80 + PIXEL31_10 + } + else + { + PIXEL20_12 + PIXEL21_0 + PIXEL30_20 + PIXEL31_11 + } + PIXEL22_0 + if (Diff(w[6], w[8])) + { + PIXEL23_0 + PIXEL32_0 + PIXEL33_0 + } + else + { + PIXEL23_50 + PIXEL32_50 + PIXEL33_50 + } + break; + } + case 158: + { + if (Diff(w[4], w[2])) + { + PIXEL00_80 + PIXEL01_10 + PIXEL10_10 + PIXEL11_30 + } + else + { + PIXEL00_20 + PIXEL01_12 + PIXEL10_11 + PIXEL11_0 + } + if (Diff(w[2], w[6])) + { + PIXEL02_0 + PIXEL03_0 + PIXEL13_0 + } + else + { + PIXEL02_50 + PIXEL03_50 + PIXEL13_50 + } + PIXEL12_0 + PIXEL20_10 + PIXEL21_30 + PIXEL22_32 + PIXEL23_32 + PIXEL30_80 + PIXEL31_61 + PIXEL32_82 + PIXEL33_82 + break; + } + case 234: + { + if (Diff(w[4], w[2])) + { + PIXEL00_80 + PIXEL01_10 + PIXEL10_10 + PIXEL11_30 + } + else + { + PIXEL00_20 + PIXEL01_12 + PIXEL10_11 + PIXEL11_0 + } + PIXEL02_10 + PIXEL03_80 + PIXEL12_30 + PIXEL13_61 + if (Diff(w[8], w[4])) + { + PIXEL20_0 + PIXEL30_0 + PIXEL31_0 + } + else + { + PIXEL20_50 + PIXEL30_50 + PIXEL31_50 + } + PIXEL21_0 + PIXEL22_31 + PIXEL23_81 + PIXEL32_31 + PIXEL33_81 + break; + } + case 242: + { + PIXEL00_80 + PIXEL01_10 + if (Diff(w[2], w[6])) + { + PIXEL02_10 + PIXEL03_80 + PIXEL12_30 + PIXEL13_10 + } + else + { + PIXEL02_11 + PIXEL03_20 + PIXEL12_0 + PIXEL13_12 + } + PIXEL10_61 + PIXEL11_30 + PIXEL20_82 + PIXEL21_32 + PIXEL22_0 + if (Diff(w[6], w[8])) + { + PIXEL23_0 + PIXEL32_0 + PIXEL33_0 + } + else + { + PIXEL23_50 + PIXEL32_50 + PIXEL33_50 + } + PIXEL30_82 + PIXEL31_32 + break; + } + case 59: + { + if (Diff(w[4], w[2])) + { + PIXEL00_0 + PIXEL01_0 + PIXEL10_0 + } + else + { + PIXEL00_50 + PIXEL01_50 + PIXEL10_50 + } + if (Diff(w[2], w[6])) + { + PIXEL02_10 + PIXEL03_80 + PIXEL12_30 + PIXEL13_10 + } + else + { + PIXEL02_11 + PIXEL03_20 + PIXEL12_0 + PIXEL13_12 + } + PIXEL11_0 + PIXEL20_31 + PIXEL21_31 + PIXEL22_30 + PIXEL23_10 + PIXEL30_81 + PIXEL31_81 + PIXEL32_61 + PIXEL33_80 + break; + } + case 121: + { + PIXEL00_82 + PIXEL01_82 + PIXEL02_61 + PIXEL03_80 + PIXEL10_32 + PIXEL11_32 + PIXEL12_30 + PIXEL13_10 + if (Diff(w[8], w[4])) + { + PIXEL20_0 + PIXEL30_0 + PIXEL31_0 + } + else + { + PIXEL20_50 + PIXEL30_50 + PIXEL31_50 + } + PIXEL21_0 + if (Diff(w[6], w[8])) + { + PIXEL22_30 + PIXEL23_10 + PIXEL32_10 + PIXEL33_80 + } + else + { + PIXEL22_0 + PIXEL23_11 + PIXEL32_12 + PIXEL33_20 + } + break; + } + case 87: + { + PIXEL00_81 + PIXEL01_31 + if (Diff(w[2], w[6])) + { + PIXEL02_0 + PIXEL03_0 + PIXEL13_0 + } + else + { + PIXEL02_50 + PIXEL03_50 + PIXEL13_50 + } + PIXEL10_81 + PIXEL11_31 + PIXEL12_0 + PIXEL20_61 + PIXEL21_30 + if (Diff(w[6], w[8])) + { + PIXEL22_30 + PIXEL23_10 + PIXEL32_10 + PIXEL33_80 + } + else + { + PIXEL22_0 + PIXEL23_11 + PIXEL32_12 + PIXEL33_20 + } + PIXEL30_80 + PIXEL31_10 + break; + } + case 79: + { + if (Diff(w[4], w[2])) + { + PIXEL00_0 + PIXEL01_0 + PIXEL10_0 + } + else + { + PIXEL00_50 + PIXEL01_50 + PIXEL10_50 + } + PIXEL02_32 + PIXEL03_82 + PIXEL11_0 + PIXEL12_32 + PIXEL13_82 + if (Diff(w[8], w[4])) + { + PIXEL20_10 + PIXEL21_30 + PIXEL30_80 + PIXEL31_10 + } + else + { + PIXEL20_12 + PIXEL21_0 + PIXEL30_20 + PIXEL31_11 + } + PIXEL22_30 + PIXEL23_61 + PIXEL32_10 + PIXEL33_80 + break; + } + case 122: + { + if (Diff(w[4], w[2])) + { + PIXEL00_80 + PIXEL01_10 + PIXEL10_10 + PIXEL11_30 + } + else + { + PIXEL00_20 + PIXEL01_12 + PIXEL10_11 + PIXEL11_0 + } + if (Diff(w[2], w[6])) + { + PIXEL02_10 + PIXEL03_80 + PIXEL12_30 + PIXEL13_10 + } + else + { + PIXEL02_11 + PIXEL03_20 + PIXEL12_0 + PIXEL13_12 + } + if (Diff(w[8], w[4])) + { + PIXEL20_0 + PIXEL30_0 + PIXEL31_0 + } + else + { + PIXEL20_50 + PIXEL30_50 + PIXEL31_50 + } + PIXEL21_0 + if (Diff(w[6], w[8])) + { + PIXEL22_30 + PIXEL23_10 + PIXEL32_10 + PIXEL33_80 + } + else + { + PIXEL22_0 + PIXEL23_11 + PIXEL32_12 + PIXEL33_20 + } + break; + } + case 94: + { + if (Diff(w[4], w[2])) + { + PIXEL00_80 + PIXEL01_10 + PIXEL10_10 + PIXEL11_30 + } + else + { + PIXEL00_20 + PIXEL01_12 + PIXEL10_11 + PIXEL11_0 + } + if (Diff(w[2], w[6])) + { + PIXEL02_0 + PIXEL03_0 + PIXEL13_0 + } + else + { + PIXEL02_50 + PIXEL03_50 + PIXEL13_50 + } + PIXEL12_0 + if (Diff(w[8], w[4])) + { + PIXEL20_10 + PIXEL21_30 + PIXEL30_80 + PIXEL31_10 + } + else + { + PIXEL20_12 + PIXEL21_0 + PIXEL30_20 + PIXEL31_11 + } + if (Diff(w[6], w[8])) + { + PIXEL22_30 + PIXEL23_10 + PIXEL32_10 + PIXEL33_80 + } + else + { + PIXEL22_0 + PIXEL23_11 + PIXEL32_12 + PIXEL33_20 + } + break; + } + case 218: + { + if (Diff(w[4], w[2])) + { + PIXEL00_80 + PIXEL01_10 + PIXEL10_10 + PIXEL11_30 + } + else + { + PIXEL00_20 + PIXEL01_12 + PIXEL10_11 + PIXEL11_0 + } + if (Diff(w[2], w[6])) + { + PIXEL02_10 + PIXEL03_80 + PIXEL12_30 + PIXEL13_10 + } + else + { + PIXEL02_11 + PIXEL03_20 + PIXEL12_0 + PIXEL13_12 + } + if (Diff(w[8], w[4])) + { + PIXEL20_10 + PIXEL21_30 + PIXEL30_80 + PIXEL31_10 + } + else + { + PIXEL20_12 + PIXEL21_0 + PIXEL30_20 + PIXEL31_11 + } + PIXEL22_0 + if (Diff(w[6], w[8])) + { + PIXEL23_0 + PIXEL32_0 + PIXEL33_0 + } + else + { + PIXEL23_50 + PIXEL32_50 + PIXEL33_50 + } + break; + } + case 91: + { + if (Diff(w[4], w[2])) + { + PIXEL00_0 + PIXEL01_0 + PIXEL10_0 + } + else + { + PIXEL00_50 + PIXEL01_50 + PIXEL10_50 + } + if (Diff(w[2], w[6])) + { + PIXEL02_10 + PIXEL03_80 + PIXEL12_30 + PIXEL13_10 + } + else + { + PIXEL02_11 + PIXEL03_20 + PIXEL12_0 + PIXEL13_12 + } + PIXEL11_0 + if (Diff(w[8], w[4])) + { + PIXEL20_10 + PIXEL21_30 + PIXEL30_80 + PIXEL31_10 + } + else + { + PIXEL20_12 + PIXEL21_0 + PIXEL30_20 + PIXEL31_11 + } + if (Diff(w[6], w[8])) + { + PIXEL22_30 + PIXEL23_10 + PIXEL32_10 + PIXEL33_80 + } + else + { + PIXEL22_0 + PIXEL23_11 + PIXEL32_12 + PIXEL33_20 + } + break; + } + case 229: + { + PIXEL00_20 + PIXEL01_60 + PIXEL02_60 + PIXEL03_20 + PIXEL10_60 + PIXEL11_70 + PIXEL12_70 + PIXEL13_60 + PIXEL20_82 + PIXEL21_32 + PIXEL22_31 + PIXEL23_81 + PIXEL30_82 + PIXEL31_32 + PIXEL32_31 + PIXEL33_81 + break; + } + case 167: + { + PIXEL00_81 + PIXEL01_31 + PIXEL02_32 + PIXEL03_82 + PIXEL10_81 + PIXEL11_31 + PIXEL12_32 + PIXEL13_82 + PIXEL20_60 + PIXEL21_70 + PIXEL22_70 + PIXEL23_60 + PIXEL30_20 + PIXEL31_60 + PIXEL32_60 + PIXEL33_20 + break; + } + case 173: + { + PIXEL00_82 + PIXEL01_82 + PIXEL02_60 + PIXEL03_20 + PIXEL10_32 + PIXEL11_32 + PIXEL12_70 + PIXEL13_60 + PIXEL20_31 + PIXEL21_31 + PIXEL22_70 + PIXEL23_60 + PIXEL30_81 + PIXEL31_81 + PIXEL32_60 + PIXEL33_20 + break; + } + case 181: + { + PIXEL00_20 + PIXEL01_60 + PIXEL02_81 + PIXEL03_81 + PIXEL10_60 + PIXEL11_70 + PIXEL12_31 + PIXEL13_31 + PIXEL20_60 + PIXEL21_70 + PIXEL22_32 + PIXEL23_32 + PIXEL30_20 + PIXEL31_60 + PIXEL32_82 + PIXEL33_82 + break; + } + case 186: + { + if (Diff(w[4], w[2])) + { + PIXEL00_80 + PIXEL01_10 + PIXEL10_10 + PIXEL11_30 + } + else + { + PIXEL00_20 + PIXEL01_12 + PIXEL10_11 + PIXEL11_0 + } + if (Diff(w[2], w[6])) + { + PIXEL02_10 + PIXEL03_80 + PIXEL12_30 + PIXEL13_10 + } + else + { + PIXEL02_11 + PIXEL03_20 + PIXEL12_0 + PIXEL13_12 + } + PIXEL20_31 + PIXEL21_31 + PIXEL22_32 + PIXEL23_32 + PIXEL30_81 + PIXEL31_81 + PIXEL32_82 + PIXEL33_82 + break; + } + case 115: + { + PIXEL00_81 + PIXEL01_31 + if (Diff(w[2], w[6])) + { + PIXEL02_10 + PIXEL03_80 + PIXEL12_30 + PIXEL13_10 + } + else + { + PIXEL02_11 + PIXEL03_20 + PIXEL12_0 + PIXEL13_12 + } + PIXEL10_81 + PIXEL11_31 + PIXEL20_82 + PIXEL21_32 + if (Diff(w[6], w[8])) + { + PIXEL22_30 + PIXEL23_10 + PIXEL32_10 + PIXEL33_80 + } + else + { + PIXEL22_0 + PIXEL23_11 + PIXEL32_12 + PIXEL33_20 + } + PIXEL30_82 + PIXEL31_32 + break; + } + case 93: + { + PIXEL00_82 + PIXEL01_82 + PIXEL02_81 + PIXEL03_81 + PIXEL10_32 + PIXEL11_32 + PIXEL12_31 + PIXEL13_31 + if (Diff(w[8], w[4])) + { + PIXEL20_10 + PIXEL21_30 + PIXEL30_80 + PIXEL31_10 + } + else + { + PIXEL20_12 + PIXEL21_0 + PIXEL30_20 + PIXEL31_11 + } + if (Diff(w[6], w[8])) + { + PIXEL22_30 + PIXEL23_10 + PIXEL32_10 + PIXEL33_80 + } + else + { + PIXEL22_0 + PIXEL23_11 + PIXEL32_12 + PIXEL33_20 + } + break; + } + case 206: + { + if (Diff(w[4], w[2])) + { + PIXEL00_80 + PIXEL01_10 + PIXEL10_10 + PIXEL11_30 + } + else + { + PIXEL00_20 + PIXEL01_12 + PIXEL10_11 + PIXEL11_0 + } + PIXEL02_32 + PIXEL03_82 + PIXEL12_32 + PIXEL13_82 + if (Diff(w[8], w[4])) + { + PIXEL20_10 + PIXEL21_30 + PIXEL30_80 + PIXEL31_10 + } + else + { + PIXEL20_12 + PIXEL21_0 + PIXEL30_20 + PIXEL31_11 + } + PIXEL22_31 + PIXEL23_81 + PIXEL32_31 + PIXEL33_81 + break; + } + case 205: + case 201: + { + PIXEL00_82 + PIXEL01_82 + PIXEL02_60 + PIXEL03_20 + PIXEL10_32 + PIXEL11_32 + PIXEL12_70 + PIXEL13_60 + if (Diff(w[8], w[4])) + { + PIXEL20_10 + PIXEL21_30 + PIXEL30_80 + PIXEL31_10 + } + else + { + PIXEL20_12 + PIXEL21_0 + PIXEL30_20 + PIXEL31_11 + } + PIXEL22_31 + PIXEL23_81 + PIXEL32_31 + PIXEL33_81 + break; + } + case 174: + case 46: + { + if (Diff(w[4], w[2])) + { + PIXEL00_80 + PIXEL01_10 + PIXEL10_10 + PIXEL11_30 + } + else + { + PIXEL00_20 + PIXEL01_12 + PIXEL10_11 + PIXEL11_0 + } + PIXEL02_32 + PIXEL03_82 + PIXEL12_32 + PIXEL13_82 + PIXEL20_31 + PIXEL21_31 + PIXEL22_70 + PIXEL23_60 + PIXEL30_81 + PIXEL31_81 + PIXEL32_60 + PIXEL33_20 + break; + } + case 179: + case 147: + { + PIXEL00_81 + PIXEL01_31 + if (Diff(w[2], w[6])) + { + PIXEL02_10 + PIXEL03_80 + PIXEL12_30 + PIXEL13_10 + } + else + { + PIXEL02_11 + PIXEL03_20 + PIXEL12_0 + PIXEL13_12 + } + PIXEL10_81 + PIXEL11_31 + PIXEL20_60 + PIXEL21_70 + PIXEL22_32 + PIXEL23_32 + PIXEL30_20 + PIXEL31_60 + PIXEL32_82 + PIXEL33_82 + break; + } + case 117: + case 116: + { + PIXEL00_20 + PIXEL01_60 + PIXEL02_81 + PIXEL03_81 + PIXEL10_60 + PIXEL11_70 + PIXEL12_31 + PIXEL13_31 + PIXEL20_82 + PIXEL21_32 + if (Diff(w[6], w[8])) + { + PIXEL22_30 + PIXEL23_10 + PIXEL32_10 + PIXEL33_80 + } + else + { + PIXEL22_0 + PIXEL23_11 + PIXEL32_12 + PIXEL33_20 + } + PIXEL30_82 + PIXEL31_32 + break; + } + case 189: + { + PIXEL00_82 + PIXEL01_82 + PIXEL02_81 + PIXEL03_81 + PIXEL10_32 + PIXEL11_32 + PIXEL12_31 + PIXEL13_31 + PIXEL20_31 + PIXEL21_31 + PIXEL22_32 + PIXEL23_32 + PIXEL30_81 + PIXEL31_81 + PIXEL32_82 + PIXEL33_82 + break; + } + case 231: + { + PIXEL00_81 + PIXEL01_31 + PIXEL02_32 + PIXEL03_82 + PIXEL10_81 + PIXEL11_31 + PIXEL12_32 + PIXEL13_82 + PIXEL20_82 + PIXEL21_32 + PIXEL22_31 + PIXEL23_81 + PIXEL30_82 + PIXEL31_32 + PIXEL32_31 + PIXEL33_81 + break; + } + case 126: + { + PIXEL00_80 + PIXEL01_10 + if (Diff(w[2], w[6])) + { + PIXEL02_0 + PIXEL03_0 + PIXEL13_0 + } + else + { + PIXEL02_50 + PIXEL03_50 + PIXEL13_50 + } + PIXEL10_10 + PIXEL11_30 + PIXEL12_0 + if (Diff(w[8], w[4])) + { + PIXEL20_0 + PIXEL30_0 + PIXEL31_0 + } + else + { + PIXEL20_50 + PIXEL30_50 + PIXEL31_50 + } + PIXEL21_0 + PIXEL22_30 + PIXEL23_10 + PIXEL32_10 + PIXEL33_80 + break; + } + case 219: + { + if (Diff(w[4], w[2])) + { + PIXEL00_0 + PIXEL01_0 + PIXEL10_0 + } + else + { + PIXEL00_50 + PIXEL01_50 + PIXEL10_50 + } + PIXEL02_10 + PIXEL03_80 + PIXEL11_0 + PIXEL12_30 + PIXEL13_10 + PIXEL20_10 + PIXEL21_30 + PIXEL22_0 + if (Diff(w[6], w[8])) + { + PIXEL23_0 + PIXEL32_0 + PIXEL33_0 + } + else + { + PIXEL23_50 + PIXEL32_50 + PIXEL33_50 + } + PIXEL30_80 + PIXEL31_10 + break; + } + case 125: + { + if (Diff(w[8], w[4])) + { + PIXEL00_82 + PIXEL10_32 + PIXEL20_0 + PIXEL21_0 + PIXEL30_0 + PIXEL31_0 + } + else + { + PIXEL00_11 + PIXEL10_13 + PIXEL20_83 + PIXEL21_70 + PIXEL30_50 + PIXEL31_21 + } + PIXEL01_82 + PIXEL02_81 + PIXEL03_81 + PIXEL11_32 + PIXEL12_31 + PIXEL13_31 + PIXEL22_30 + PIXEL23_10 + PIXEL32_10 + PIXEL33_80 + break; + } + case 221: + { + PIXEL00_82 + PIXEL01_82 + PIXEL02_81 + if (Diff(w[6], w[8])) + { + PIXEL03_81 + PIXEL13_31 + PIXEL22_0 + PIXEL23_0 + PIXEL32_0 + PIXEL33_0 + } + else + { + PIXEL03_12 + PIXEL13_14 + PIXEL22_70 + PIXEL23_83 + PIXEL32_21 + PIXEL33_50 + } + PIXEL10_32 + PIXEL11_32 + PIXEL12_31 + PIXEL20_10 + PIXEL21_30 + PIXEL30_80 + PIXEL31_10 + break; + } + case 207: + { + if (Diff(w[4], w[2])) + { + PIXEL00_0 + PIXEL01_0 + PIXEL02_32 + PIXEL03_82 + PIXEL10_0 + PIXEL11_0 + } + else + { + PIXEL00_50 + PIXEL01_83 + PIXEL02_13 + PIXEL03_11 + PIXEL10_21 + PIXEL11_70 + } + PIXEL12_32 + PIXEL13_82 + PIXEL20_10 + PIXEL21_30 + PIXEL22_31 + PIXEL23_81 + PIXEL30_80 + PIXEL31_10 + PIXEL32_31 + PIXEL33_81 + break; + } + case 238: + { + PIXEL00_80 + PIXEL01_10 + PIXEL02_32 + PIXEL03_82 + PIXEL10_10 + PIXEL11_30 + PIXEL12_32 + PIXEL13_82 + if (Diff(w[8], w[4])) + { + PIXEL20_0 + PIXEL21_0 + PIXEL30_0 + PIXEL31_0 + PIXEL32_31 + PIXEL33_81 + } + else + { + PIXEL20_21 + PIXEL21_70 + PIXEL30_50 + PIXEL31_83 + PIXEL32_14 + PIXEL33_12 + } + PIXEL22_31 + PIXEL23_81 + break; + } + case 190: + { + PIXEL00_80 + PIXEL01_10 + if (Diff(w[2], w[6])) + { + PIXEL02_0 + PIXEL03_0 + PIXEL12_0 + PIXEL13_0 + PIXEL23_32 + PIXEL33_82 + } + else + { + PIXEL02_21 + PIXEL03_50 + PIXEL12_70 + PIXEL13_83 + PIXEL23_13 + PIXEL33_11 + } + PIXEL10_10 + PIXEL11_30 + PIXEL20_31 + PIXEL21_31 + PIXEL22_32 + PIXEL30_81 + PIXEL31_81 + PIXEL32_82 + break; + } + case 187: + { + if (Diff(w[4], w[2])) + { + PIXEL00_0 + PIXEL01_0 + PIXEL10_0 + PIXEL11_0 + PIXEL20_31 + PIXEL30_81 + } + else + { + PIXEL00_50 + PIXEL01_21 + PIXEL10_83 + PIXEL11_70 + PIXEL20_14 + PIXEL30_12 + } + PIXEL02_10 + PIXEL03_80 + PIXEL12_30 + PIXEL13_10 + PIXEL21_31 + PIXEL22_32 + PIXEL23_32 + PIXEL31_81 + PIXEL32_82 + PIXEL33_82 + break; + } + case 243: + { + PIXEL00_81 + PIXEL01_31 + PIXEL02_10 + PIXEL03_80 + PIXEL10_81 + PIXEL11_31 + PIXEL12_30 + PIXEL13_10 + PIXEL20_82 + PIXEL21_32 + if (Diff(w[6], w[8])) + { + PIXEL22_0 + PIXEL23_0 + PIXEL30_82 + PIXEL31_32 + PIXEL32_0 + PIXEL33_0 + } + else + { + PIXEL22_70 + PIXEL23_21 + PIXEL30_11 + PIXEL31_13 + PIXEL32_83 + PIXEL33_50 + } + break; + } + case 119: + { + if (Diff(w[2], w[6])) + { + PIXEL00_81 + PIXEL01_31 + PIXEL02_0 + PIXEL03_0 + PIXEL12_0 + PIXEL13_0 + } + else + { + PIXEL00_12 + PIXEL01_14 + PIXEL02_83 + PIXEL03_50 + PIXEL12_70 + PIXEL13_21 + } + PIXEL10_81 + PIXEL11_31 + PIXEL20_82 + PIXEL21_32 + PIXEL22_30 + PIXEL23_10 + PIXEL30_82 + PIXEL31_32 + PIXEL32_10 + PIXEL33_80 + break; + } + case 237: + case 233: + { + PIXEL00_82 + PIXEL01_82 + PIXEL02_60 + PIXEL03_20 + PIXEL10_32 + PIXEL11_32 + PIXEL12_70 + PIXEL13_60 + PIXEL20_0 + PIXEL21_0 + PIXEL22_31 + PIXEL23_81 + if (Diff(w[8], w[4])) + { + PIXEL30_0 + } + else + { + PIXEL30_20 + } + PIXEL31_0 + PIXEL32_31 + PIXEL33_81 + break; + } + case 175: + case 47: + { + if (Diff(w[4], w[2])) + { + PIXEL00_0 + } + else + { + PIXEL00_20 + } + PIXEL01_0 + PIXEL02_32 + PIXEL03_82 + PIXEL10_0 + PIXEL11_0 + PIXEL12_32 + PIXEL13_82 + PIXEL20_31 + PIXEL21_31 + PIXEL22_70 + PIXEL23_60 + PIXEL30_81 + PIXEL31_81 + PIXEL32_60 + PIXEL33_20 + break; + } + case 183: + case 151: + { + PIXEL00_81 + PIXEL01_31 + PIXEL02_0 + if (Diff(w[2], w[6])) + { + PIXEL03_0 + } + else + { + PIXEL03_20 + } + PIXEL10_81 + PIXEL11_31 + PIXEL12_0 + PIXEL13_0 + PIXEL20_60 + PIXEL21_70 + PIXEL22_32 + PIXEL23_32 + PIXEL30_20 + PIXEL31_60 + PIXEL32_82 + PIXEL33_82 + break; + } + case 245: + case 244: + { + PIXEL00_20 + PIXEL01_60 + PIXEL02_81 + PIXEL03_81 + PIXEL10_60 + PIXEL11_70 + PIXEL12_31 + PIXEL13_31 + PIXEL20_82 + PIXEL21_32 + PIXEL22_0 + PIXEL23_0 + PIXEL30_82 + PIXEL31_32 + PIXEL32_0 + if (Diff(w[6], w[8])) + { + PIXEL33_0 + } + else + { + PIXEL33_20 + } + break; + } + case 250: + { + PIXEL00_80 + PIXEL01_10 + PIXEL02_10 + PIXEL03_80 + PIXEL10_10 + PIXEL11_30 + PIXEL12_30 + PIXEL13_10 + if (Diff(w[8], w[4])) + { + PIXEL20_0 + PIXEL30_0 + PIXEL31_0 + } + else + { + PIXEL20_50 + PIXEL30_50 + PIXEL31_50 + } + PIXEL21_0 + PIXEL22_0 + if (Diff(w[6], w[8])) + { + PIXEL23_0 + PIXEL32_0 + PIXEL33_0 + } + else + { + PIXEL23_50 + PIXEL32_50 + PIXEL33_50 + } + break; + } + case 123: + { + if (Diff(w[4], w[2])) + { + PIXEL00_0 + PIXEL01_0 + PIXEL10_0 + } + else + { + PIXEL00_50 + PIXEL01_50 + PIXEL10_50 + } + PIXEL02_10 + PIXEL03_80 + PIXEL11_0 + PIXEL12_30 + PIXEL13_10 + if (Diff(w[8], w[4])) + { + PIXEL20_0 + PIXEL30_0 + PIXEL31_0 + } + else + { + PIXEL20_50 + PIXEL30_50 + PIXEL31_50 + } + PIXEL21_0 + PIXEL22_30 + PIXEL23_10 + PIXEL32_10 + PIXEL33_80 + break; + } + case 95: + { + if (Diff(w[4], w[2])) + { + PIXEL00_0 + PIXEL01_0 + PIXEL10_0 + } + else + { + PIXEL00_50 + PIXEL01_50 + PIXEL10_50 + } + if (Diff(w[2], w[6])) + { + PIXEL02_0 + PIXEL03_0 + PIXEL13_0 + } + else + { + PIXEL02_50 + PIXEL03_50 + PIXEL13_50 + } + PIXEL11_0 + PIXEL12_0 + PIXEL20_10 + PIXEL21_30 + PIXEL22_30 + PIXEL23_10 + PIXEL30_80 + PIXEL31_10 + PIXEL32_10 + PIXEL33_80 + break; + } + case 222: + { + PIXEL00_80 + PIXEL01_10 + if (Diff(w[2], w[6])) + { + PIXEL02_0 + PIXEL03_0 + PIXEL13_0 + } + else + { + PIXEL02_50 + PIXEL03_50 + PIXEL13_50 + } + PIXEL10_10 + PIXEL11_30 + PIXEL12_0 + PIXEL20_10 + PIXEL21_30 + PIXEL22_0 + if (Diff(w[6], w[8])) + { + PIXEL23_0 + PIXEL32_0 + PIXEL33_0 + } + else + { + PIXEL23_50 + PIXEL32_50 + PIXEL33_50 + } + PIXEL30_80 + PIXEL31_10 + break; + } + case 252: + { + PIXEL00_80 + PIXEL01_61 + PIXEL02_81 + PIXEL03_81 + PIXEL10_10 + PIXEL11_30 + PIXEL12_31 + PIXEL13_31 + if (Diff(w[8], w[4])) + { + PIXEL20_0 + PIXEL30_0 + PIXEL31_0 + } + else + { + PIXEL20_50 + PIXEL30_50 + PIXEL31_50 + } + PIXEL21_0 + PIXEL22_0 + PIXEL23_0 + PIXEL32_0 + if (Diff(w[6], w[8])) + { + PIXEL33_0 + } + else + { + PIXEL33_20 + } + break; + } + case 249: + { + PIXEL00_82 + PIXEL01_82 + PIXEL02_61 + PIXEL03_80 + PIXEL10_32 + PIXEL11_32 + PIXEL12_30 + PIXEL13_10 + PIXEL20_0 + PIXEL21_0 + PIXEL22_0 + if (Diff(w[6], w[8])) + { + PIXEL23_0 + PIXEL32_0 + PIXEL33_0 + } + else + { + PIXEL23_50 + PIXEL32_50 + PIXEL33_50 + } + if (Diff(w[8], w[4])) + { + PIXEL30_0 + } + else + { + PIXEL30_20 + } + PIXEL31_0 + break; + } + case 235: + { + if (Diff(w[4], w[2])) + { + PIXEL00_0 + PIXEL01_0 + PIXEL10_0 + } + else + { + PIXEL00_50 + PIXEL01_50 + PIXEL10_50 + } + PIXEL02_10 + PIXEL03_80 + PIXEL11_0 + PIXEL12_30 + PIXEL13_61 + PIXEL20_0 + PIXEL21_0 + PIXEL22_31 + PIXEL23_81 + if (Diff(w[8], w[4])) + { + PIXEL30_0 + } + else + { + PIXEL30_20 + } + PIXEL31_0 + PIXEL32_31 + PIXEL33_81 + break; + } + case 111: + { + if (Diff(w[4], w[2])) + { + PIXEL00_0 + } + else + { + PIXEL00_20 + } + PIXEL01_0 + PIXEL02_32 + PIXEL03_82 + PIXEL10_0 + PIXEL11_0 + PIXEL12_32 + PIXEL13_82 + if (Diff(w[8], w[4])) + { + PIXEL20_0 + PIXEL30_0 + PIXEL31_0 + } + else + { + PIXEL20_50 + PIXEL30_50 + PIXEL31_50 + } + PIXEL21_0 + PIXEL22_30 + PIXEL23_61 + PIXEL32_10 + PIXEL33_80 + break; + } + case 63: + { + if (Diff(w[4], w[2])) + { + PIXEL00_0 + } + else + { + PIXEL00_20 + } + PIXEL01_0 + if (Diff(w[2], w[6])) + { + PIXEL02_0 + PIXEL03_0 + PIXEL13_0 + } + else + { + PIXEL02_50 + PIXEL03_50 + PIXEL13_50 + } + PIXEL10_0 + PIXEL11_0 + PIXEL12_0 + PIXEL20_31 + PIXEL21_31 + PIXEL22_30 + PIXEL23_10 + PIXEL30_81 + PIXEL31_81 + PIXEL32_61 + PIXEL33_80 + break; + } + case 159: + { + if (Diff(w[4], w[2])) + { + PIXEL00_0 + PIXEL01_0 + PIXEL10_0 + } + else + { + PIXEL00_50 + PIXEL01_50 + PIXEL10_50 + } + PIXEL02_0 + if (Diff(w[2], w[6])) + { + PIXEL03_0 + } + else + { + PIXEL03_20 + } + PIXEL11_0 + PIXEL12_0 + PIXEL13_0 + PIXEL20_10 + PIXEL21_30 + PIXEL22_32 + PIXEL23_32 + PIXEL30_80 + PIXEL31_61 + PIXEL32_82 + PIXEL33_82 + break; + } + case 215: + { + PIXEL00_81 + PIXEL01_31 + PIXEL02_0 + if (Diff(w[2], w[6])) + { + PIXEL03_0 + } + else + { + PIXEL03_20 + } + PIXEL10_81 + PIXEL11_31 + PIXEL12_0 + PIXEL13_0 + PIXEL20_61 + PIXEL21_30 + PIXEL22_0 + if (Diff(w[6], w[8])) + { + PIXEL23_0 + PIXEL32_0 + PIXEL33_0 + } + else + { + PIXEL23_50 + PIXEL32_50 + PIXEL33_50 + } + PIXEL30_80 + PIXEL31_10 + break; + } + case 246: + { + PIXEL00_80 + PIXEL01_10 + if (Diff(w[2], w[6])) + { + PIXEL02_0 + PIXEL03_0 + PIXEL13_0 + } + else + { + PIXEL02_50 + PIXEL03_50 + PIXEL13_50 + } + PIXEL10_61 + PIXEL11_30 + PIXEL12_0 + PIXEL20_82 + PIXEL21_32 + PIXEL22_0 + PIXEL23_0 + PIXEL30_82 + PIXEL31_32 + PIXEL32_0 + if (Diff(w[6], w[8])) + { + PIXEL33_0 + } + else + { + PIXEL33_20 + } + break; + } + case 254: + { + PIXEL00_80 + PIXEL01_10 + if (Diff(w[2], w[6])) + { + PIXEL02_0 + PIXEL03_0 + PIXEL13_0 + } + else + { + PIXEL02_50 + PIXEL03_50 + PIXEL13_50 + } + PIXEL10_10 + PIXEL11_30 + PIXEL12_0 + if (Diff(w[8], w[4])) + { + PIXEL20_0 + PIXEL30_0 + PIXEL31_0 + } + else + { + PIXEL20_50 + PIXEL30_50 + PIXEL31_50 + } + PIXEL21_0 + PIXEL22_0 + PIXEL23_0 + PIXEL32_0 + if (Diff(w[6], w[8])) + { + PIXEL33_0 + } + else + { + PIXEL33_20 + } + break; + } + case 253: + { + PIXEL00_82 + PIXEL01_82 + PIXEL02_81 + PIXEL03_81 + PIXEL10_32 + PIXEL11_32 + PIXEL12_31 + PIXEL13_31 + PIXEL20_0 + PIXEL21_0 + PIXEL22_0 + PIXEL23_0 + if (Diff(w[8], w[4])) + { + PIXEL30_0 + } + else + { + PIXEL30_20 + } + PIXEL31_0 + PIXEL32_0 + if (Diff(w[6], w[8])) + { + PIXEL33_0 + } + else + { + PIXEL33_20 + } + break; + } + case 251: + { + if (Diff(w[4], w[2])) + { + PIXEL00_0 + PIXEL01_0 + PIXEL10_0 + } + else + { + PIXEL00_50 + PIXEL01_50 + PIXEL10_50 + } + PIXEL02_10 + PIXEL03_80 + PIXEL11_0 + PIXEL12_30 + PIXEL13_10 + PIXEL20_0 + PIXEL21_0 + PIXEL22_0 + if (Diff(w[6], w[8])) + { + PIXEL23_0 + PIXEL32_0 + PIXEL33_0 + } + else + { + PIXEL23_50 + PIXEL32_50 + PIXEL33_50 + } + if (Diff(w[8], w[4])) + { + PIXEL30_0 + } + else + { + PIXEL30_20 + } + PIXEL31_0 + break; + } + case 239: + { + if (Diff(w[4], w[2])) + { + PIXEL00_0 + } + else + { + PIXEL00_20 + } + PIXEL01_0 + PIXEL02_32 + PIXEL03_82 + PIXEL10_0 + PIXEL11_0 + PIXEL12_32 + PIXEL13_82 + PIXEL20_0 + PIXEL21_0 + PIXEL22_31 + PIXEL23_81 + if (Diff(w[8], w[4])) + { + PIXEL30_0 + } + else + { + PIXEL30_20 + } + PIXEL31_0 + PIXEL32_31 + PIXEL33_81 + break; + } + case 127: + { + if (Diff(w[4], w[2])) + { + PIXEL00_0 + } + else + { + PIXEL00_20 + } + PIXEL01_0 + if (Diff(w[2], w[6])) + { + PIXEL02_0 + PIXEL03_0 + PIXEL13_0 + } + else + { + PIXEL02_50 + PIXEL03_50 + PIXEL13_50 + } + PIXEL10_0 + PIXEL11_0 + PIXEL12_0 + if (Diff(w[8], w[4])) + { + PIXEL20_0 + PIXEL30_0 + PIXEL31_0 + } + else + { + PIXEL20_50 + PIXEL30_50 + PIXEL31_50 + } + PIXEL21_0 + PIXEL22_30 + PIXEL23_10 + PIXEL32_10 + PIXEL33_80 + break; + } + case 191: + { + if (Diff(w[4], w[2])) + { + PIXEL00_0 + } + else + { + PIXEL00_20 + } + PIXEL01_0 + PIXEL02_0 + if (Diff(w[2], w[6])) + { + PIXEL03_0 + } + else + { + PIXEL03_20 + } + PIXEL10_0 + PIXEL11_0 + PIXEL12_0 + PIXEL13_0 + PIXEL20_31 + PIXEL21_31 + PIXEL22_32 + PIXEL23_32 + PIXEL30_81 + PIXEL31_81 + PIXEL32_82 + PIXEL33_82 + break; + } + case 223: + { + if (Diff(w[4], w[2])) + { + PIXEL00_0 + PIXEL01_0 + PIXEL10_0 + } + else + { + PIXEL00_50 + PIXEL01_50 + PIXEL10_50 + } + PIXEL02_0 + if (Diff(w[2], w[6])) + { + PIXEL03_0 + } + else + { + PIXEL03_20 + } + PIXEL11_0 + PIXEL12_0 + PIXEL13_0 + PIXEL20_10 + PIXEL21_30 + PIXEL22_0 + if (Diff(w[6], w[8])) + { + PIXEL23_0 + PIXEL32_0 + PIXEL33_0 + } + else + { + PIXEL23_50 + PIXEL32_50 + PIXEL33_50 + } + PIXEL30_80 + PIXEL31_10 + break; + } + case 247: + { + PIXEL00_81 + PIXEL01_31 + PIXEL02_0 + if (Diff(w[2], w[6])) + { + PIXEL03_0 + } + else + { + PIXEL03_20 + } + PIXEL10_81 + PIXEL11_31 + PIXEL12_0 + PIXEL13_0 + PIXEL20_82 + PIXEL21_32 + PIXEL22_0 + PIXEL23_0 + PIXEL30_82 + PIXEL31_32 + PIXEL32_0 + if (Diff(w[6], w[8])) + { + PIXEL33_0 + } + else + { + PIXEL33_20 + } + break; + } + case 255: + { + if (Diff(w[4], w[2])) + { + PIXEL00_0 + } + else + { + PIXEL00_20 + } + PIXEL01_0 + PIXEL02_0 + if (Diff(w[2], w[6])) + { + PIXEL03_0 + } + else + { + PIXEL03_20 + } + PIXEL10_0 + PIXEL11_0 + PIXEL12_0 + PIXEL13_0 + PIXEL20_0 + PIXEL21_0 + PIXEL22_0 + PIXEL23_0 + if (Diff(w[8], w[4])) + { + PIXEL30_0 + } + else + { + PIXEL30_20 + } + PIXEL31_0 + PIXEL32_0 + if (Diff(w[6], w[8])) + { + PIXEL33_0 + } + else + { + PIXEL33_20 + } + break; + } + } + pIn+=2; + pOut+=16; + } + pOut+=BpL; + pOut+=BpL; + pOut+=BpL; + } +} + +void InitHQ4X(void) +{ + int i, j, k, r, g, b, Y, u, v; + + for (i=0; i<65536; i++) + LUT16to32[i] = ((i & 0xF800) << 8) + ((i & 0x07E0) << 5) + ((i & 0x001F) << 3); + + for (i=0; i<32; i++) + for (j=0; j<64; j++) + for (k=0; k<32; k++) + { + r = i << 3; + g = j << 2; + b = k << 3; + Y = (r + g + b) >> 2; + u = 128 + ((r - b) >> 2); + v = 128 + ((-r + 2*g -b)>>3); + RGBtoYUV[ (i << 11) + (j << 5) + k ] = (Y<<16) + (u<<8) + v; + } +} + diff --git a/engines/vileVN/external/hq4x/hq4x.h b/engines/vileVN/external/hq4x/hq4x.h new file mode 100644 index 0000000000..dc996f59f1 --- /dev/null +++ b/engines/vileVN/external/hq4x/hq4x.h @@ -0,0 +1,9 @@ +#ifndef _HQ4X_H_ +#define _HQ4X_H_ + +extern void InitHQ4X(void); +extern void hq4x_32(unsigned char *In, + unsigned char *Out,int Xres,int Yres,int BpL); + +#endif + diff --git a/engines/vileVN/external/utf8cpp/checked.h b/engines/vileVN/external/utf8cpp/checked.h new file mode 100644 index 0000000000..9cb8d2c7f2 --- /dev/null +++ b/engines/vileVN/external/utf8cpp/checked.h @@ -0,0 +1,327 @@ +// Copyright 2006 Nemanja Trifunovic + +/* +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +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, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + + +#ifndef UTF8_FOR_CPP_CHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 +#define UTF8_FOR_CPP_CHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 + +#include "core.h" +#include + +namespace utf8 +{ + // Base for the exceptions that may be thrown from the library + class exception : public std::exception { + }; + + // Exceptions that may be thrown from the library functions. + class invalid_code_point : public exception { + uint32_t cp; + public: + invalid_code_point(uint32_t cp) : cp(cp) {} + virtual const char* what() const throw() { return "Invalid code point"; } + uint32_t code_point() const {return cp;} + }; + + class invalid_utf8 : public exception { + uint8_t u8; + public: + invalid_utf8 (uint8_t u) : u8(u) {} + virtual const char* what() const throw() { return "Invalid UTF-8"; } + uint8_t utf8_octet() const {return u8;} + }; + + class invalid_utf16 : public exception { + uint16_t u16; + public: + invalid_utf16 (uint16_t u) : u16(u) {} + virtual const char* what() const throw() { return "Invalid UTF-16"; } + uint16_t utf16_word() const {return u16;} + }; + + class not_enough_room : public exception { + public: + virtual const char* what() const throw() { return "Not enough space"; } + }; + + /// The library API - functions intended to be called by the users + + template + output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out, uint32_t replacement) + { + while (start != end) { + octet_iterator sequence_start = start; + internal::utf_error err_code = internal::validate_next(start, end); + switch (err_code) { + case internal::UTF8_OK : + for (octet_iterator it = sequence_start; it != start; ++it) + *out++ = *it; + break; + case internal::NOT_ENOUGH_ROOM: + throw not_enough_room(); + case internal::INVALID_LEAD: + append (replacement, out); + ++start; + break; + case internal::INCOMPLETE_SEQUENCE: + case internal::OVERLONG_SEQUENCE: + case internal::INVALID_CODE_POINT: + append (replacement, out); + ++start; + // just one replacement mark for the sequence + while (internal::is_trail(*start) && start != end) + ++start; + break; + } + } + return out; + } + + template + inline output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out) + { + static const uint32_t replacement_marker = internal::mask16(0xfffd); + return replace_invalid(start, end, out, replacement_marker); + } + + template + octet_iterator append(uint32_t cp, octet_iterator result) + { + if (!internal::is_code_point_valid(cp)) + throw invalid_code_point(cp); + + if (cp < 0x80) // one octet + *(result++) = static_cast(cp); + else if (cp < 0x800) { // two octets + *(result++) = static_cast((cp >> 6) | 0xc0); + *(result++) = static_cast((cp & 0x3f) | 0x80); + } + else if (cp < 0x10000) { // three octets + *(result++) = static_cast((cp >> 12) | 0xe0); + *(result++) = static_cast(((cp >> 6) & 0x3f) | 0x80); + *(result++) = static_cast((cp & 0x3f) | 0x80); + } + else { // four octets + *(result++) = static_cast((cp >> 18) | 0xf0); + *(result++) = static_cast(((cp >> 12) & 0x3f) | 0x80); + *(result++) = static_cast(((cp >> 6) & 0x3f) | 0x80); + *(result++) = static_cast((cp & 0x3f) | 0x80); + } + return result; + } + + template + uint32_t next(octet_iterator& it, octet_iterator end) + { + uint32_t cp = 0; + internal::utf_error err_code = internal::validate_next(it, end, &cp); + switch (err_code) { + case internal::UTF8_OK : + break; + case internal::NOT_ENOUGH_ROOM : + throw not_enough_room(); + case internal::INVALID_LEAD : + case internal::INCOMPLETE_SEQUENCE : + case internal::OVERLONG_SEQUENCE : + throw invalid_utf8(*it); + case internal::INVALID_CODE_POINT : + throw invalid_code_point(cp); + } + return cp; + } + + template + uint32_t peek_next(octet_iterator it, octet_iterator end) + { + return next(it, end); + } + + template + uint32_t prior(octet_iterator& it, octet_iterator start) + { + // can't do much if it == start + if (it == start) + throw not_enough_room(); + + octet_iterator end = it; + // Go back until we hit either a lead octet or start + while (internal::is_trail(*(--it))) + if (it == start) + throw invalid_utf8(*it); // error - no lead byte in the sequence + return peek_next(it, end); + } + + /// Deprecated in versions that include "prior" + template + uint32_t previous(octet_iterator& it, octet_iterator pass_start) + { + octet_iterator end = it; + while (internal::is_trail(*(--it))) + if (it == pass_start) + throw invalid_utf8(*it); // error - no lead byte in the sequence + octet_iterator temp = it; + return next(temp, end); + } + + template + void advance (octet_iterator& it, distance_type n, octet_iterator end) + { + for (distance_type i = 0; i < n; ++i) + next(it, end); + } + + template + typename std::iterator_traits::difference_type + distance (octet_iterator first, octet_iterator last) + { + typename std::iterator_traits::difference_type dist; + for (dist = 0; first < last; ++dist) + next(first, last); + return dist; + } + + template + octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result) + { + while (start != end) { + uint32_t cp = internal::mask16(*start++); + // Take care of surrogate pairs first + if (internal::is_lead_surrogate(cp)) { + if (start != end) { + uint32_t trail_surrogate = internal::mask16(*start++); + if (internal::is_trail_surrogate(trail_surrogate)) + cp = (cp << 10) + trail_surrogate + internal::SURROGATE_OFFSET; + else + throw invalid_utf16(static_cast(trail_surrogate)); + } + else + throw invalid_utf16(static_cast(cp)); + + } + // Lone trail surrogate + else if (internal::is_trail_surrogate(cp)) + throw invalid_utf16(static_cast(cp)); + + result = append(cp, result); + } + return result; + } + + template + u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result) + { + while (start != end) { + uint32_t cp = next(start, end); + if (cp > 0xffff) { //make a surrogate pair + *result++ = static_cast((cp >> 10) + internal::LEAD_OFFSET); + *result++ = static_cast((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN); + } + else + *result++ = static_cast(cp); + } + return result; + } + + template + octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result) + { + while (start != end) + result = append(*(start++), result); + + return result; + } + + template + u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result) + { + while (start != end) + (*result++) = next(start, end); + + return result; + } + + // The iterator class + template + class iterator : public std::iterator { + octet_iterator it; + octet_iterator range_start; + octet_iterator range_end; + public: + iterator () {}; + explicit iterator (const octet_iterator& octet_it, + const octet_iterator& range_start, + const octet_iterator& range_end) : + it(octet_it), range_start(range_start), range_end(range_end) + { + if (it < range_start || it > range_end) + throw std::out_of_range("Invalid utf-8 iterator position"); + } + // the default "big three" are OK + octet_iterator base () const { return it; } + uint32_t operator * () const + { + octet_iterator temp = it; + return next(temp, range_end); + } + bool operator == (const iterator& rhs) const + { + if (range_start != rhs.range_start || range_end != rhs.range_end) + throw std::logic_error("Comparing utf-8 iterators defined with different ranges"); + return (it == rhs.it); + } + bool operator != (const iterator& rhs) const + { + return !(operator == (rhs)); + } + iterator& operator ++ () + { + next(it, range_end); + return *this; + } + iterator operator ++ (int) + { + iterator temp = *this; + next(it, range_end); + return temp; + } + iterator& operator -- () + { + prior(it, range_start); + return *this; + } + iterator operator -- (int) + { + iterator temp = *this; + prior(it, range_start); + return temp; + } + }; // class iterator + +} // namespace utf8 + +#endif //header guard + + diff --git a/engines/vileVN/external/utf8cpp/core.h b/engines/vileVN/external/utf8cpp/core.h new file mode 100755 index 0000000000..268cf7cd48 --- /dev/null +++ b/engines/vileVN/external/utf8cpp/core.h @@ -0,0 +1,358 @@ +// Copyright 2006 Nemanja Trifunovic + +/* +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +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, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + + +#ifndef UTF8_FOR_CPP_CORE_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 +#define UTF8_FOR_CPP_CORE_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 + +#include + +namespace utf8 +{ + // The typedefs for 8-bit, 16-bit and 32-bit unsigned integers + // You may need to change them to match your system. + // These typedefs have the same names as ones from cstdint, or boost/cstdint + typedef unsigned char uint8_t; + typedef unsigned short uint16_t; + typedef unsigned int uint32_t; + +// Helper code - not intended to be directly called by the library users. May be changed at any time +namespace internal +{ + // Unicode constants + // Leading (high) surrogates: 0xd800 - 0xdbff + // Trailing (low) surrogates: 0xdc00 - 0xdfff + const uint16_t LEAD_SURROGATE_MIN = 0xd800u; + const uint16_t LEAD_SURROGATE_MAX = 0xdbffu; + const uint16_t TRAIL_SURROGATE_MIN = 0xdc00u; + const uint16_t TRAIL_SURROGATE_MAX = 0xdfffu; + const uint16_t LEAD_OFFSET = LEAD_SURROGATE_MIN - (0x10000 >> 10); + const uint32_t SURROGATE_OFFSET = 0x10000u - (LEAD_SURROGATE_MIN << 10) - TRAIL_SURROGATE_MIN; + + // Maximum valid value for a Unicode code point + const uint32_t CODE_POINT_MAX = 0x0010ffffu; + + template + inline uint8_t mask8(octet_type oc) + { + return static_cast(0xff & oc); + } + template + inline uint16_t mask16(u16_type oc) + { + return static_cast(0xffff & oc); + } + template + inline bool is_trail(octet_type oc) + { + return ((mask8(oc) >> 6) == 0x2); + } + + template + inline bool is_lead_surrogate(u16 cp) + { + return (cp >= LEAD_SURROGATE_MIN && cp <= LEAD_SURROGATE_MAX); + } + + template + inline bool is_trail_surrogate(u16 cp) + { + return (cp >= TRAIL_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX); + } + + template + inline bool is_surrogate(u16 cp) + { + return (cp >= LEAD_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX); + } + + template + inline bool is_code_point_valid(u32 cp) + { + return (cp <= CODE_POINT_MAX && !is_surrogate(cp)); + } + + template + inline typename std::iterator_traits::difference_type + sequence_length(octet_iterator lead_it) + { + uint8_t lead = mask8(*lead_it); + if (lead < 0x80) + return 1; + else if ((lead >> 5) == 0x6) + return 2; + else if ((lead >> 4) == 0xe) + return 3; + else if ((lead >> 3) == 0x1e) + return 4; + else + return 0; + } + + template + inline bool is_overlong_sequence(uint32_t cp, octet_difference_type length) + { + if (cp < 0x80) { + if (length != 1) + return true; + } + else if (cp < 0x800) { + if (length != 2) + return true; + } + else if (cp < 0x10000) { + if (length != 3) + return true; + } + + return false; + } + + enum utf_error {UTF8_OK, NOT_ENOUGH_ROOM, INVALID_LEAD, INCOMPLETE_SEQUENCE, OVERLONG_SEQUENCE, INVALID_CODE_POINT}; + + /// get_sequence_x functions decode utf-8 sequences of the length x + + template + utf_error get_sequence_1(octet_iterator& it, octet_iterator end, uint32_t* code_point) + { + if (it != end) { + if (code_point) + *code_point = mask8(*it); + return UTF8_OK; + } + return NOT_ENOUGH_ROOM; + } + + template + utf_error get_sequence_2(octet_iterator& it, octet_iterator end, uint32_t* code_point) + { + utf_error ret_code = NOT_ENOUGH_ROOM; + + if (it != end) { + uint32_t cp = mask8(*it); + if (++it != end) { + if (is_trail(*it)) { + cp = ((cp << 6) & 0x7ff) + ((*it) & 0x3f); + + if (code_point) + *code_point = cp; + ret_code = UTF8_OK; + } + else + ret_code = INCOMPLETE_SEQUENCE; + } + else + ret_code = NOT_ENOUGH_ROOM; + } + + return ret_code; + } + + template + utf_error get_sequence_3(octet_iterator& it, octet_iterator end, uint32_t* code_point) + { + utf_error ret_code = NOT_ENOUGH_ROOM; + + if (it != end) { + uint32_t cp = mask8(*it); + if (++it != end) { + if (is_trail(*it)) { + cp = ((cp << 12) & 0xffff) + ((mask8(*it) << 6) & 0xfff); + if (++it != end) { + if (is_trail(*it)) { + cp += (*it) & 0x3f; + + if (code_point) + *code_point = cp; + ret_code = UTF8_OK; + } + else + ret_code = INCOMPLETE_SEQUENCE; + } + else + ret_code = NOT_ENOUGH_ROOM; + } + else + ret_code = INCOMPLETE_SEQUENCE; + } + else + ret_code = NOT_ENOUGH_ROOM; + } + + return ret_code; + } + + template + utf_error get_sequence_4(octet_iterator& it, octet_iterator end, uint32_t* code_point) + { + utf_error ret_code = NOT_ENOUGH_ROOM; + + if (it != end) { + uint32_t cp = mask8(*it); + if (++it != end) { + if (is_trail(*it)) { + cp = ((cp << 18) & 0x1fffff) + ((mask8(*it) << 12) & 0x3ffff); + if (++it != end) { + if (is_trail(*it)) { + cp += (mask8(*it) << 6) & 0xfff; + if (++it != end) { + if (is_trail(*it)) { + cp += (*it) & 0x3f; + + if (code_point) + *code_point = cp; + ret_code = UTF8_OK; + } + else + ret_code = INCOMPLETE_SEQUENCE; + } + else + ret_code = NOT_ENOUGH_ROOM; + } + else + ret_code = INCOMPLETE_SEQUENCE; + } + else + ret_code = NOT_ENOUGH_ROOM; + } + else + ret_code = INCOMPLETE_SEQUENCE; + } + else + ret_code = NOT_ENOUGH_ROOM; + } + + return ret_code; + } + + template + utf_error validate_next(octet_iterator& it, octet_iterator end, uint32_t* code_point) + { + // Save the original value of it so we can go back in case of failure + // Of course, it does not make much sense with i.e. stream iterators + octet_iterator original_it = it; + + uint32_t cp = 0; + // Determine the sequence length based on the lead octet + typedef typename std::iterator_traits::difference_type octet_difference_type; + octet_difference_type length = sequence_length(it); + if (length == 0) + return INVALID_LEAD; + + // Now that we have a valid sequence length, get trail octets and calculate the code point + utf_error err = UTF8_OK; + switch (length) { + case 1: + err = get_sequence_1(it, end, &cp); + break; + case 2: + err = get_sequence_2(it, end, &cp); + break; + case 3: + err = get_sequence_3(it, end, &cp); + break; + case 4: + err = get_sequence_4(it, end, &cp); + break; + } + + if (err == UTF8_OK) { + // Decoding succeeded. Now, security checks... + if (is_code_point_valid(cp)) { + if (!is_overlong_sequence(cp, length)){ + // Passed! Return here. + if (code_point) + *code_point = cp; + ++it; + return UTF8_OK; + } + else + err = OVERLONG_SEQUENCE; + } + else + err = INVALID_CODE_POINT; + } + + // Failure branch - restore the original value of the iterator + it = original_it; + return err; + } + + template + inline utf_error validate_next(octet_iterator& it, octet_iterator end) { + return validate_next(it, end, 0); + } + +} // namespace internal + + /// The library API - functions intended to be called by the users + + // Byte order mark + const uint8_t bom[] = {0xef, 0xbb, 0xbf}; + + template + octet_iterator find_invalid(octet_iterator start, octet_iterator end) + { + octet_iterator result = start; + while (result != end) { + internal::utf_error err_code = internal::validate_next(result, end); + if (err_code != internal::UTF8_OK) + return result; + } + return result; + } + + template + inline bool is_valid(octet_iterator start, octet_iterator end) + { + return (find_invalid(start, end) == end); + } + + template + inline bool starts_with_bom (octet_iterator it, octet_iterator end) + { + return ( + ((it != end) && (internal::mask8(*it++)) == bom[0]) && + ((it != end) && (internal::mask8(*it++)) == bom[1]) && + ((it != end) && (internal::mask8(*it)) == bom[2]) + ); + } + + //Deprecated in release 2.3 + template + inline bool is_bom (octet_iterator it) + { + return ( + (internal::mask8(*it++)) == bom[0] && + (internal::mask8(*it++)) == bom[1] && + (internal::mask8(*it)) == bom[2] + ); + } +} // namespace utf8 + +#endif // header guard + + diff --git a/engines/vileVN/external/utf8cpp/unchecked.h b/engines/vileVN/external/utf8cpp/unchecked.h new file mode 100755 index 0000000000..2f3eb4d1d0 --- /dev/null +++ b/engines/vileVN/external/utf8cpp/unchecked.h @@ -0,0 +1,228 @@ +// Copyright 2006 Nemanja Trifunovic + +/* +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +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, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + + +#ifndef UTF8_FOR_CPP_UNCHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 +#define UTF8_FOR_CPP_UNCHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 + +#include "core.h" + +namespace utf8 +{ + namespace unchecked + { + template + octet_iterator append(uint32_t cp, octet_iterator result) + { + if (cp < 0x80) // one octet + *(result++) = static_cast(cp); + else if (cp < 0x800) { // two octets + *(result++) = static_cast((cp >> 6) | 0xc0); + *(result++) = static_cast((cp & 0x3f) | 0x80); + } + else if (cp < 0x10000) { // three octets + *(result++) = static_cast((cp >> 12) | 0xe0); + *(result++) = static_cast(((cp >> 6) & 0x3f) | 0x80); + *(result++) = static_cast((cp & 0x3f) | 0x80); + } + else { // four octets + *(result++) = static_cast((cp >> 18) | 0xf0); + *(result++) = static_cast(((cp >> 12) & 0x3f)| 0x80); + *(result++) = static_cast(((cp >> 6) & 0x3f) | 0x80); + *(result++) = static_cast((cp & 0x3f) | 0x80); + } + return result; + } + + template + uint32_t next(octet_iterator& it) + { + uint32_t cp = internal::mask8(*it); + typename std::iterator_traits::difference_type length = utf8::internal::sequence_length(it); + switch (length) { + case 1: + break; + case 2: + it++; + cp = ((cp << 6) & 0x7ff) + ((*it) & 0x3f); + break; + case 3: + ++it; + cp = ((cp << 12) & 0xffff) + ((internal::mask8(*it) << 6) & 0xfff); + ++it; + cp += (*it) & 0x3f; + break; + case 4: + ++it; + cp = ((cp << 18) & 0x1fffff) + ((internal::mask8(*it) << 12) & 0x3ffff); + ++it; + cp += (internal::mask8(*it) << 6) & 0xfff; + ++it; + cp += (*it) & 0x3f; + break; + } + ++it; + return cp; + } + + template + uint32_t peek_next(octet_iterator it) + { + return next(it); + } + + template + uint32_t prior(octet_iterator& it) + { + while (internal::is_trail(*(--it))) ; + octet_iterator temp = it; + return next(temp); + } + + // Deprecated in versions that include prior, but only for the sake of consistency (see utf8::previous) + template + inline uint32_t previous(octet_iterator& it) + { + return prior(it); + } + + template + void advance (octet_iterator& it, distance_type n) + { + for (distance_type i = 0; i < n; ++i) + next(it); + } + + template + typename std::iterator_traits::difference_type + distance (octet_iterator first, octet_iterator last) + { + typename std::iterator_traits::difference_type dist; + for (dist = 0; first < last; ++dist) + next(first); + return dist; + } + + template + octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result) + { + while (start != end) { + uint32_t cp = internal::mask16(*start++); + // Take care of surrogate pairs first + if (internal::is_lead_surrogate(cp)) { + uint32_t trail_surrogate = internal::mask16(*start++); + cp = (cp << 10) + trail_surrogate + internal::SURROGATE_OFFSET; + } + result = append(cp, result); + } + return result; + } + + template + u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result) + { + while (start < end) { + uint32_t cp = next(start); + if (cp > 0xffff) { //make a surrogate pair + *result++ = static_cast((cp >> 10) + internal::LEAD_OFFSET); + *result++ = static_cast((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN); + } + else + *result++ = static_cast(cp); + } + return result; + } + + template + octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result) + { + while (start != end) + result = append(*(start++), result); + + return result; + } + + template + u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result) + { + while (start < end) + (*result++) = next(start); + + return result; + } + + // The iterator class + template + class iterator : public std::iterator { + octet_iterator it; + public: + iterator () {}; + explicit iterator (const octet_iterator& octet_it): it(octet_it) {} + // the default "big three" are OK + octet_iterator base () const { return it; } + uint32_t operator * () const + { + octet_iterator temp = it; + return next(temp); + } + bool operator == (const iterator& rhs) const + { + return (it == rhs.it); + } + bool operator != (const iterator& rhs) const + { + return !(operator == (rhs)); + } + iterator& operator ++ () + { + std::advance(it, internal::sequence_length(it)); + return *this; + } + iterator operator ++ (int) + { + iterator temp = *this; + std::advance(it, internal::sequence_length(it)); + return temp; + } + iterator& operator -- () + { + prior(it); + return *this; + } + iterator operator -- (int) + { + iterator temp = *this; + prior(it); + return temp; + } + }; // class iterator + + } // namespace utf8::unchecked +} // namespace utf8 + + +#endif // header guard + diff --git a/engines/vileVN/ikura/catgirl/catgirl.cpp b/engines/vileVN/ikura/catgirl/catgirl.cpp new file mode 100644 index 0000000000..0b88da2efc --- /dev/null +++ b/engines/vileVN/ikura/catgirl/catgirl.cpp @@ -0,0 +1,111 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "catgirl.h" + +CatGirl::CatGirl(uString Path) : IkuraDecoder(640,480){ + // Load resources + AddScripts(new ArchiveIkura(Path+"ISF")); + AddImages(new ArchiveIkura(Path+"GGD")); + AddVoices(new ArchiveIkura(Path+"VOICE")); + AddSE(new ArchiveIkura(Path+"SE")); + AddBGM(new ArchiveIkura(Path+"WMSC")); + AddVideo(new ArchiveFiles(Path+"LOGO.MPG")); + AddOther(new ArchiveIkura(Path+"DATA")); + CreateTextview(); + + // Load standard boot script + RunScript("START.ISF"); +} + +const uString CatGirl::NativeID(){ + return "CATGIRL"; +} + +const uString CatGirl::NativeName(){ + return "Cat Girl Alliance"; +} + +void CatGirl::CreateTextview(){ + // Load textwindow graphic and prepare widget + w_textview->SetTextPosition(15,40,610,105); + SDL_Surface *tmpsurface=LoadImage("M_WIN.GGP"); + SDL_Surface *autobutton=LoadImage("M_AUTO.GGP"); + SDL_Surface *skipbutton=LoadImage("M_SKIP.GGP"); + SDL_Surface *menubutton=LoadImage("M_MENU.GGP"); + + if(tmpsurface && autobutton && skipbutton && menubutton){ + // Set window graphics + w_textview->Resize(tmpsurface->w,tmpsurface->h); + w_textview->Set(tmpsurface); + + // Size of individual buttons + int bw=96; + int bh=36; + + // Skip checkbox + ValueButton *w_skip=new ValueButton(); + SDL_Rect skipclear={0,bh*4,bw,bh}; + SDL_Rect skiphover={0,bh*2,bw,bh}; + SDL_Rect skipset={0,bh*3,bw,bh}; + SDL_Rect skipnormal={0,bh,bw,bh}; + SDL_Rect skip={0,0,bw,bh}; + w_skip->Move(352,0); + w_skip->Resize(bw,bh); + w_skip->SetState(WS_NORMAL,skipbutton,&skip,skipbutton,&skipnormal); + w_skip->SetState(WS_HOVER,skipbutton,&skip,skipbutton,&skiphover); + w_skip->SetState(WS_SELECT,skipbutton,&skip,skipbutton,&skipset); + w_skip->SetState(WS_DISABLE,skipbutton,&skip,skipbutton,&skipclear); + w_textview->SetSkipButton(w_skip); + + // Autobutton + BitmapButton *w_auto=new BitmapButton(); + w_auto->Move(352+bw,0); + w_auto->Resize(bw,bh); + w_auto->SetState(WS_NORMAL,autobutton,0,bh*1,bw,bh); + w_auto->SetState(WS_HOVER,autobutton,0,bh*2,bw,bh); + w_auto->SetState(WS_SELECT,autobutton,0,bh*3,bw,bh); + w_auto->SetState(WS_DISABLE,autobutton,0,bh*4,bw,bh); + w_textview->SetAutoButton(w_auto); + + // Menubutton + BitmapButton *w_option=new BitmapButton(); + w_option->Move(352+bw*2,0); + w_option->Resize(bw,bh); + w_option->SetState(WS_NORMAL,menubutton,0,bh*1,bw,bh); + w_option->SetState(WS_HOVER,menubutton,0,bh*2,bw,bh); + w_option->SetState(WS_SELECT,menubutton,0,bh*3,bw,bh); + w_option->SetState(WS_DISABLE,menubutton,0,bh*4,bw,bh); + w_textview->SetOptionButton(w_option); + + // Clean up temporary surfaces + SDL_FreeSurface(skipbutton); + SDL_FreeSurface(autobutton); + SDL_FreeSurface(menubutton); + SDL_FreeSurface(tmpsurface); + } + else{ + LogError("Failed to load textview graphics"); + } +} + +/*TODO: + GET FLAGS SAVING AND LOADING PROPERLY + Get the title screen working. Game currently boots and immediately starts a new game. + Reconfigure the menu button to pop up the sub-menu + Get the animated "next page" indicator in the bottom-right working + Derive a method to set save names + */ + diff --git a/engines/vileVN/ikura/catgirl/catgirl.h b/engines/vileVN/ikura/catgirl/catgirl.h new file mode 100644 index 0000000000..2924a3160c --- /dev/null +++ b/engines/vileVN/ikura/catgirl/catgirl.h @@ -0,0 +1,22 @@ +/*! \class CatGirl + * \brief Loader class for Cat Girl Alliance + */ +#ifndef _CATGIRL_H_ +#define _CATGIRL_H_ + +#include "../ikuradecoder.h" + +class CatGirl : public IkuraDecoder { + private: + // Override game attributes + const uString NativeID(); + const uString NativeName(); + + // Macro for fancy textview + void CreateTextview(); + public: + CatGirl(uString Path); +}; + +#endif + diff --git a/engines/vileVN/ikura/crescendo/crescendo.cpp b/engines/vileVN/ikura/crescendo/crescendo.cpp new file mode 100644 index 0000000000..244ddddf2e --- /dev/null +++ b/engines/vileVN/ikura/crescendo/crescendo.cpp @@ -0,0 +1,49 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "crescendo.h" + +Crescendo::Crescendo(uString Path) : IkuraDecoder(640,480){ + // Load resources + AddScripts(new ArchiveIkura(Path+"ISF")); + AddImages(new ArchiveIkura(Path+"GGD")); + AddVoices(new ArchiveIkura(Path+"VOICE")); + AddSE(new ArchiveIkura(Path+"SE")); + AddBGM(new ArchiveIkura(Path+"WMSC")); + AddBGM(new ArchiveIkura(Path+"MIDI")); + AddVideo(new ArchiveFiles(Path+"DOLOGO.MPG")); + AddOther(new ArchiveFiles(Path+"*.suf")); + + // Load standard boot script + RunScript("START.ISF"); +} + +const uString Crescendo::NativeID(){ + return "Crescendo"; +} + +const uString Crescendo::NativeName(){ + return "Crescendo"; +} + +/*! \brief Ignore textview configuration for this game + * \param Data Ignored + * \param Length Ignored + * \return False + */ +bool Crescendo::iop_wp(const Uint8 *Data,int Length){ + return false; +} + diff --git a/engines/vileVN/ikura/crescendo/crescendo.h b/engines/vileVN/ikura/crescendo/crescendo.h new file mode 100644 index 0000000000..23259cd521 --- /dev/null +++ b/engines/vileVN/ikura/crescendo/crescendo.h @@ -0,0 +1,22 @@ +/*! \class Crescendo + * \brief Loader class for the Ikuragame + */ +#ifndef _CRESCENDO_H_ +#define _CRESCENDO_H_ + +#include "../ikuradecoder.h" + +class Crescendo : public IkuraDecoder { + private: + // Override game attributes + virtual const uString NativeID(); + virtual const uString NativeName(); + + // Override opcode handlers + virtual bool iop_wp(const Uint8 *Data,int Length); + public: + Crescendo(uString Path); +}; + +#endif + diff --git a/engines/vileVN/ikura/drsdecoder.cpp b/engines/vileVN/ikura/drsdecoder.cpp new file mode 100644 index 0000000000..840ba0a782 --- /dev/null +++ b/engines/vileVN/ikura/drsdecoder.cpp @@ -0,0 +1,508 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "drsdecoder.h" + +DRSDecoder::DRSDecoder(int Width,int Height) : IkuraDecoder(Width,Height){ + w_display->SetTarget(1); +} + +DRSDecoder::~DRSDecoder(){ +} + +/*! \brief Advances the scripted engine + * \returns True if the engine is waiting for user input + */ +bool DRSDecoder::EventGameProcess(){ + Uint8 c; + Uint32 l; + const Uint8 *b; + bool r=true; + if(parser.GetOpcode(&c,&b,&l)){ + // DRS specifies length off by one + if(l){ + l--; + } + LogTest("OPCODE %02X (%d bytes)",c,l); + + // Map opcode between ikura and drs handlers + if(c==0x00) r=iop_ed(b,l); + else if(c==0x01) r=iop_ls(b,l); + else if(c==0x02) r=OP02(b,l); + else if(c==0x03) r=OP03(b,l); + else if(c==0x04) r=iop_jp(b,l); + else if(c==0x05) r=OP05(b,l); + else if(c==0x06) r=OP06(b,l); + else if(c==0x07) r=OP07(b,l); + else if(c==0x08) r=OP08(b,l); + else if(c==0x09) r=iop_setgameinfo(b,l); + //else if(c==0x0A) r=OP0A(b,l); + //else if(c==0x0B) r=OP0B(b,l); + else if(c==0x0C) r=OP0C(b,l); + else if(c==0x0D) r=OP0D(b,l); + else if(c==0x0E) r=OP0E(b,l); + else if(c==0x10) r=iop_cw(b,l); + else if(c==0x11) r=OP11(b,l); + //else if(c==0x12) r=OP12(b,l); + //else if(c==0x13) r=OP13(b,l); + else if(c==0x14) r=iop_cset(b,l); + else if(c==0x15) r=OP15(b,l); + else if(c==0x16) r=iop_cwc(b,l); + else if(c==0x17) r=iop_cc(b,l); + else if(c==0x20) r=OP20(b,l); + else if(c==0x21) r=OP21(b,l); + //else if(c==0x22) r=OP22(b,l); + else if(c==0x28) r=iop_wo(b,l); + else if(c==0x29) r=iop_wc(b,l); + else if(c==0x2A) r=OP2A(b,l); + else if(c==0x2B) r=OP2B(b,l); + else if(c==0x2C) r=OP2C(b,l); + //else if(c==0x30) r=iop_fln(b,l); + else if(c==0x31) r=iop_sk(b,l); + else if(c==0x32) r=iop_sks(b,l); + else if(c==0x34) r=iop_hf(b,l); + else if(c==0x35) r=iop_sp(b,l); + else if(c==0x36) r=iop_pf(b,l); + else if(c==0x37) r=iop_sts(b,l); + else if(c==0x39) r=iop_es(b,l); + else if(c==0x3A) r=iop_ec(b,l); + else if(c==0x3C) r=OP3C(b,l); + else if(c==0x3D) r=OP3D(b,l); + //else if(c==0x40) r=iop_hln(b,l); + else if(c==0x41) r=iop_hs(b,l); + else if(c==0x42) r=OP42(b,l); + else if(c==0x43) r=iop_hinc(b,l); + else if(c==0x44) r=iop_hdec(b,l); + else if(c==0x46) r=OP46(b,l); + else if(c==0x47) r=OP47(b,l); + else if(c==0x50) r=iop_vset(b,l); + else if(c==0x51) r=iop_gn(b,l); + else if(c==0x53) r=iop_gc(b,l); + else if(c==0x54) r=OP54(b,l); + else if(c==0x55) r=OP55(b,l); + else if(c==0x56) r=iop_gp(b,l); + else if(c==0x76) r=iop_ser(b,l); + else if(c==0x77) r=OP77(b,l); + else if(c==0x78) r=iop_set(b,l); + else if(c==0x79) r=OP79(b,l); + else if(c==0x7A) r=iop_dap(b,l); + else if(c==0x7B) r=iop_das(b,l); + else if(c==0x80) r=iop_im(b,l); + //else if(c==0x81) r=iop_ic(b,l); + else if(c==0x84) r=iop_ih(b,l); + else if(c==0x85) r=iop_ig(b,l); + else if(c==0xF1) r=iop_atimes(b,l); + else if(c==0xF2) r=iop_await(b,l); + else if(c==0xF3) r=OPF3(b,l); + else if(c==0xF4) r=iop_ppf(b,l); + else if(c==0xF5) r=iop_svf(b,l); + else if(c==0xF6) r=iop_opsl(b,l); + else if(c==0xF8) r=OPF8(b,l); + else if(c==0xF9) r=OPF9(b,l); + else if(c==0xFA) r=OPFA(b,l); + else r=iop_unknown(c,b,l); + } + return r; +} + +// Load script and CALL it (IOP_LSBS) +// An extra word before the script name compared to ikura +bool DRSDecoder::OP02(const Uint8 *Data,int Length){ + RWops *blob=0; + if((blob=LoadScript((char*)Data+2,"ISF"))){ + int tlength=blob->Seek(0,SEEK_END); + if(tlength>(int)0){ + blob->Seek(0,SEEK_SET); + Uint8 *tbuffer=new Uint8[tlength]; + if(blob->Read(tbuffer,tlength)>(int)0){ + DecodeScript(tbuffer,tlength); + parser.CallScript((char*)Data+2,tbuffer,tlength); + } + delete [] tbuffer; + } + delete blob; + } + return false; +} + +// Return from call (IOP_SRET) +bool DRSDecoder::OP03(const Uint8 *Data,int Length){ + parser.ReturnScript(); + return false; +} + +// Call subroutine ssoffset+jumptable[WORD] (IOP_JS) +// An extra word before the script address +bool DRSDecoder::OP05(const Uint8 *Data,int Length){ + Uint16 tableentry=GETWORD(Data+2); + parser.CallFunction(tableentry); + return false; +} + +// Return from subroute (IOP_RT) +bool DRSDecoder::OP06(const Uint8 *Data,int Length){ + parser.ReturnFunction(); + return false; +} + +// Jumpswitch (IOP_ONJP) +// Cnt is now a word +bool DRSDecoder::OP07(const Uint8 *Data,int Length){ + int reg=parser.DecodeValue(GETDWORD(Data)); + Uint16 cnt=GETWORD(Data+4); + if(reg>=(int)0 && reg=(int)0 && regSetFontSize(size); + } + return false; +} + +// Open command screen (IOP_CWO) +bool DRSDecoder::OP15(const Uint8 *Data,int Length){ + // Decode parameters + //int par=parser.DecodeValue(GETDWORD(Data)); + if(w_select){ + w_select->SetVisible(true); + selresult=-1; + } + return true; +} + +// Set text window position (IOP_WS) +// Completely off +bool DRSDecoder::OP20(const Uint8 *Data,int Length){ + Uint8 dst=GETBYTE(Data); + if(dst){ + LogError("ILLEGAL TARGET WINDOW: %d",dst); + } + Uint32 x=GETDWORD(Data+1); + Uint32 y=GETDWORD(Data+5); + Uint32 w=GETDWORD(Data+9); + Uint32 h=GETDWORD(Data+13); + w_textview->MoveDialog(x,y); + if(w && h){ + w_textview->Resize(w,h); + } + return false; +} + + +// Set text window graphic (IOP_WP) +// Much simpler than Ikura +bool DRSDecoder::OP21(const Uint8 *Data,int Length){ + // Get provided text window data + Uint8 dst=GETBYTE(Data); + char *filename=(char*)Data+2; + int width=parser.DecodeValue(GETDWORD(Data+Length-8)); + int height=parser.DecodeValue(GETDWORD(Data+Length-4)); + if(dst){ + LogError("ILLEGAL WINDOW: %d",dst); + } + else{ + SDL_Surface *tmpsurface=LoadImage(filename); + if(tmpsurface){ + w_textview->Resize(width,height); + w_textview->Set(tmpsurface); + SDL_FreeSurface(tmpsurface); + } + } + return false; +} + +// Show text window (IOP_WSS) +bool DRSDecoder::OP2A(const Uint8 *Data,int Length){ + // Set text window dimensions + Uint8 dst=GETBYTE(Data); + if(dst){ + LogError("ILLEGAL WINDOW: %d",dst); + } + else{ + w_textview->SetVisible(true); + } + return false; +} + +// Hide text window (IOP_WSH) +bool DRSDecoder::OP2B(const Uint8 *Data,int Length){ + // Set text window dimensions + Uint8 dst=GETBYTE(Data); + if(dst){ + LogError("ILLEGAL WINDOW: %d",dst); + } + else{ + w_textview->SetVisible(false); + } + return false; +} + +// Print text messages (IOP_PM) +bool DRSDecoder::OP2C(const Uint8 *Data,int Length){ + // Set text window dimensions + Uint8 dst=GETBYTE(Data); + //Uint16 length=GETWORD(Data+1); + if(dst){ + LogError("ILLEGAL WINDOW: %d",dst); + } + else{ + // Print text (Stripping unicode encoding) + uString text; + for(int j=3;Data[j];j++){ + if(Data[j]<0x7F){ + text+=(char)Data[j]; + } + } + w_textview->SetVisible(true); + w_textview->PrintText(text.c_str()); + } + return true; +} + +bool DRSDecoder::OP3C(const Uint8 *Data,int Length){ + LogTest("OP3C:CGFLAG:%d",Length); + return false; +} + +bool DRSDecoder::OP3D(const Uint8 *Data,int Length){ + LogTest("OP3D:CGFLAG:%d",Length); + return false; +} + +// Set group of variables (IOP_HSG) +bool DRSDecoder::OP42(const Uint8 *Data,int Length){ + if(iop_check(8,IOP_HSG,Data,Length)){ + // Extract iteration data + Uint16 start=GETWORD(Data); + Uint16 end=GETWORD(Data+2); + int value=parser.DecodeValue(GETDWORD(Data+4)); + + // Set group of variables + for(int i=start;i0){ + cmd=GETBYTE(Data+(offset++)); + length--; + if(cmd==0){ + v1=parser.DecodeValue(GETDWORD(Data+offset)); + length-=4; + offset+=4; + } + else{ + func=0xFF; + v1=v2=0; + if(length){ + func=GETBYTE(Data+(offset++)); + length--; + } + if(index){ + v2=values[--index]; + } + if(index){ + v1=values[--index]; + } + if(func==0) v1+=v2; + else if(func==1) v1-=v2; + else if(func==2) v1*=v2; + else if(func==3) v2?v1/=v2:0; + else if(func==4) v2?v1%=v2:0; + } + if(index<32){ + values[index++]=v1; + } + } + parser.SetValue(p,index?values[--index]:0); + return false; +} + +// If-then structure (IOP_IF) +bool DRSDecoder::OP47(const Uint8 *Data,int Length){ + Sint32 v1,v2; + Uint8 cmd; + bool flag; + int offset=0; + while(offsetv2; + else if(cmd==4) flag=v1>=v2; + else if(cmd==5) flag=v1!=v2; + + // Break on false result + if(flag==false){ + break; + } + + // Determine what to do with the result + cmd=GETBYTE(Data+(offset++)); + if(cmd==0x00){ + parser.JumpFunction(GETWORD(Data+offset)); + break; + } + if(cmd==0x01){ + return OP46(Data+offset,Length-offset); + } + if(cmd==0xFF){ + break; + } + } + return false; +} + +// Fade effect +bool DRSDecoder::OP54(const Uint8 *Data,int Length){ + Sint32 ticks=parser.DecodeValue(GETDWORD(Data+0)); + Sint32 src=parser.DecodeValue(GETDWORD(Data+4)); + Sint32 dir=parser.DecodeValue(GETDWORD(Data+8)); + if(dir){ + LogTest("FADEIN:%d:%d",ticks,src); + } + else{ + LogTest("FADEOUT:%d:%d",ticks,src); + } + return false; +} + +// Load image into the GDL buffers +bool DRSDecoder::OP55(const Uint8 *Data,int Length){ + int index=parser.DecodeValue(GETDWORD(Data)); + uString name=(char*)Data+4; + LogTest("Loading surface[%d]=%s",index,name.c_str()); + SDL_Surface *surface=LoadImage(name); + if(surface){ + w_display->SetSurface(index,surface); + SDL_FreeSurface(surface); + } + return false; +} + +// Play indexed SE (IOP_SEP) +bool DRSDecoder::OP77(const Uint8 *Data,int Length){ + int index=parser.DecodeValue(GETDWORD(Data)); + //Uint8 cmd=GETBYTE(Data+4); + LogTest("OP77:SEP:%d",index); + return false; +} + +// Play CDDA track +bool DRSDecoder::OP79(const Uint8 *Data,int Length){ + int end=parser.DecodeValue(GETDWORD(Data)); + LogTest("OP79:CDDA:%d",end); + return false; +} + +// Play video (IOP_AVIP) +bool DRSDecoder::OPF3(const Uint8 *Data,int Length){ + int srcw=parser.DecodeValue(GETDWORD(Data+0)); + int srch=parser.DecodeValue(GETDWORD(Data+4)); + int dstw=parser.DecodeValue(GETDWORD(Data+8)); + int dsth=parser.DecodeValue(GETDWORD(Data+12)); + LogVerbose("Play video: %d %d %d %d",srcw,srch,dstw,dsth); + PlayVideo((char*)Data+16); + return true; +} + +// Save enable +bool DRSDecoder::OPF8(const Uint8 *Data,int Length){ + return false; +} + +// Save disable +bool DRSDecoder::OPF9(const Uint8 *Data,int Length){ + return false; +} + +// Savedata reset +bool DRSDecoder::OPFA(const Uint8 *Data,int Length){ + return false; +} + + + + diff --git a/engines/vileVN/ikura/drsdecoder.h b/engines/vileVN/ikura/drsdecoder.h new file mode 100644 index 0000000000..7fec7ec1ad --- /dev/null +++ b/engines/vileVN/ikura/drsdecoder.h @@ -0,0 +1,54 @@ +/*! \class DRSDecoder + * \brief Engine decoder for Digital Romance System based games + * + * The Digital Romance System is the predecessor of IkuraGDL so the two + * shares many methods and most formats. The DRS system is therefore + * implemented as an override to Ikura. + */ +#ifndef _DRSDECODER_H_ +#define _DRSDECODER_H_ + +#include "ikuradecoder.h" + +class DRSDecoder : public IkuraDecoder { + protected: + // Override ikura interpreter + virtual bool EventGameProcess(); + + // drs opcode handlers + inline bool OP02(const Uint8 *Data,int Length); // Call script + inline bool OP03(const Uint8 *Data,int Length); // Return from call + inline bool OP05(const Uint8 *Data,int Length); // Call subroutine + inline bool OP06(const Uint8 *Data,int Length); // Return from sub + inline bool OP07(const Uint8 *Data,int Length); // Jumpswitch + inline bool OP08(const Uint8 *Data,int Length); // Callswitch + inline bool OP0C(const Uint8 *Data,int Length); // Read lines flags + inline bool OP0D(const Uint8 *Data,int Length); // Read lines flags + inline bool OP0E(const Uint8 *Data,int Length); // Extended flags + inline bool OP11(const Uint8 *Data,int Length); // Set font size + inline bool OP15(const Uint8 *Data,int Length); // Open window + inline bool OP20(const Uint8 *Data,int Length); // Window position + inline bool OP21(const Uint8 *Data,int Length); // Window graphics + inline bool OP2A(const Uint8 *Data,int Length); // Show window + inline bool OP2B(const Uint8 *Data,int Length); // Hide window + inline bool OP2C(const Uint8 *Data,int Length); // Print text + inline bool OP3C(const Uint8 *Data,int Length); // CG flags + inline bool OP3D(const Uint8 *Data,int Length); // CG flags + inline bool OP42(const Uint8 *Data,int Length); // Set variables + inline bool OP46(const Uint8 *Data,int Length); // Calculation + inline bool OP47(const Uint8 *Data,int Length); // If + inline bool OP54(const Uint8 *Data,int Length); // Fade effect + inline bool OP55(const Uint8 *Data,int Length); // Load image + inline bool OP77(const Uint8 *Data,int Length); // Play SE + inline bool OP79(const Uint8 *Data,int Length); // Play CDDA + inline bool OPF3(const Uint8 *Data,int Length); // Play Video + inline bool OPF8(const Uint8 *Data,int Length); // Enable save + inline bool OPF9(const Uint8 *Data,int Length); // Disable save + inline bool OPFA(const Uint8 *Data,int Length); // Reset save + public: + DRSDecoder(int Width,int Height); + ~DRSDecoder(); +}; + +#endif + diff --git a/engines/vileVN/ikura/hitomi/hitomi.cpp b/engines/vileVN/ikura/hitomi/hitomi.cpp new file mode 100644 index 0000000000..94e981e4d6 --- /dev/null +++ b/engines/vileVN/ikura/hitomi/hitomi.cpp @@ -0,0 +1,112 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "hitomi.h" + +Hitomi::Hitomi(uString Path) : IkuraDecoder(800,600){ + // Load resources + AddScripts(new ArchiveIkura(Path+"ISF")); + AddImages(new ArchiveIkura(Path+"GGD")); + AddVoices(new ArchiveIkura(Path+"VOICE")); + AddSE(new ArchiveIkura(Path+"SE")); + AddBGM(new ArchiveIkura(Path+"WMSC")); + AddVideo(new ArchiveFiles(Path+"LOGO.MPG")); + AddOther(new ArchiveIkura(Path+"DATA")); + CreateTextview(); + + // Load standard boot script + RunScript("START.ISF"); +} + +const uString Hitomi::NativeID(){ + return "HITOMI"; +} + +const uString Hitomi::NativeName(){ + return "Hitomi -My Stepsister-"; +} + +void Hitomi::CreateTextview(){ + // Load textwindow graphic and prepare widget + w_textview->SetTextPosition(15,40,770,140); + SDL_Surface *tmpsurface=LoadImage("M_WIN.GG3"); + SDL_Surface *autobutton=LoadImage("M_AUTO.GG3"); + SDL_Surface *skipbutton=LoadImage("M_SKIP.GG3"); + SDL_Surface *menubutton=LoadImage("M_MENU.GG3"); + + if(tmpsurface && autobutton && skipbutton && menubutton){ + // Set window graphics + w_textview->Resize(tmpsurface->w,tmpsurface->h); + w_textview->Set(tmpsurface); + + // Size of individual buttons + int bw=72; + int menuw=88; + int bh=40; + + // Skip checkbox + ValueButton *w_skip=new ValueButton(); + SDL_Rect skipclear={0,bh*4,bw,bh}; + SDL_Rect skiphover={0,bh*2,bw,bh}; + SDL_Rect skipset={0,bh*3,bw,bh}; + SDL_Rect skipnormal={0,bh,bw,bh}; + SDL_Rect skip={0,0,bw,bh}; + w_skip->Move(552+bw,0); + w_skip->Resize(bw,bh); + w_skip->SetState(WS_NORMAL,skipbutton,&skip,skipbutton,&skipnormal); + w_skip->SetState(WS_HOVER,skipbutton,&skip,skipbutton,&skiphover); + w_skip->SetState(WS_SELECT,skipbutton,&skip,skipbutton,&skipset); + w_skip->SetState(WS_DISABLE,skipbutton,&skip,skipbutton,&skipclear); + w_textview->SetSkipButton(w_skip); + + // Autobutton + BitmapButton *w_auto=new BitmapButton(); + w_auto->Move(552,0); + w_auto->Resize(bw,bh); + w_auto->SetState(WS_NORMAL,autobutton,0,bh*1,bw,bh); + w_auto->SetState(WS_HOVER,autobutton,0,bh*2,bw,bh); + w_auto->SetState(WS_SELECT,autobutton,0,bh*3,bw,bh); + w_auto->SetState(WS_DISABLE,autobutton,0,bh*4,bw,bh); + w_textview->SetAutoButton(w_auto); + + // Menubutton + BitmapButton *w_option=new BitmapButton(); + w_option->Move(552+bw*2,0); + w_option->Resize(menuw,bh); + w_option->SetState(WS_NORMAL,menubutton,0,bh*1,menuw,bh); + w_option->SetState(WS_HOVER,menubutton,0,bh*2,menuw,bh); + w_option->SetState(WS_SELECT,menubutton,0,bh*3,menuw,bh); + w_option->SetState(WS_DISABLE,menubutton,0,bh*4,menuw,bh); + w_textview->SetOptionButton(w_option); + + // Clean up temporary surfaces + SDL_FreeSurface(skipbutton); + SDL_FreeSurface(autobutton); + SDL_FreeSurface(menubutton); + SDL_FreeSurface(tmpsurface); + } + else{ + LogError("Failed to load textview graphics"); + } +} + +/*TODO: + Get the title screen working. Game currently boots and immediately starts a new game. + Reconfigure the menu button to pop up the sub-menu + Implement the graph view + Get the animated "next page" indicator in the bottom-right working + Derive a method to set save names + Figure out why you cannot save at decision points +*/ diff --git a/engines/vileVN/ikura/hitomi/hitomi.h b/engines/vileVN/ikura/hitomi/hitomi.h new file mode 100644 index 0000000000..172fbb12e8 --- /dev/null +++ b/engines/vileVN/ikura/hitomi/hitomi.h @@ -0,0 +1,22 @@ +/*! \class Hitomi + * \brief Loader class for Hitomi, My Stepsister + */ +#ifndef _HITOMI_H_ +#define _HITOMI_H_ + +#include "../ikuradecoder.h" + +class Hitomi : public IkuraDecoder { + private: + // Override game attributes + const uString NativeID(); + const uString NativeName(); + + // Macro for fancy textview + void CreateTextview(); + public: + Hitomi(uString Path); +}; + +#endif + diff --git a/engines/vileVN/ikura/idisplay.cpp b/engines/vileVN/ikura/idisplay.cpp new file mode 100644 index 0000000000..0ca54ea13d --- /dev/null +++ b/engines/vileVN/ikura/idisplay.cpp @@ -0,0 +1,483 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "idisplay.h" + +IkuraDisplay::IkuraDisplay(int Width,int Height) : Hotspot(){ + // Configure size + Resize(Width,Height); + + // Preset hotspot data + spots=new Group(0); + hitmap=0; + defkey=-1; + selected=-1; + result=-1; + target=0; + + // Unset graphics + isurface[0]=EDL_CreateSurface(Width,Height); + for(int i=1;iSaveSurface(name,isurface[i]); + count++; + } + } + File->SaveUint32("display-size",count); + return true; +} + +bool IkuraDisplay::Load(Savegame *File){ + for(int i=0;iLoadSurface(name,&tmpsurface)){ + isurface[i]=tmpsurface; + } + } + if(isurface[target]){ + Blit(isurface[target]); + } + return isurface[target]; +} + +bool IkuraDisplay::FocusEnter(){ + Refresh(); + return true; +} + +bool IkuraDisplay::FocusLeave(){ + Refresh(); + return true; +} + +/*! \brief Handles input test for hitmap + * \param X coordinate relative to native resolution + * \param Y coordinate relative to native resolution + * \return True if hitmap gobbled the input + */ +bool IkuraDisplay::TestMouse(int X,int Y){ + bool retval=false; + if(hitmap){ + // Find hotspots in preloaded hitmap + Uint8 *pixel = static_cast(hitmap->pixels)+ + (Y*hitmap->pitch)+(X*hitmap->format->BytesPerPixel); + if(pixel[1]!=0xFF){ + retval=true; + } + } + else{ + // Find hotspot represented by widgets + retval=spots->GetWidget(X,Y); + } + return retval; +} + +bool IkuraDisplay::MouseMove(int X,int Y){ + bool retval=false; + if(hitmap){ + // Find hotspots in preloaded hitmap + Uint8 *pixel = static_cast(hitmap->pixels)+ + (Y*hitmap->pitch)+(X*hitmap->format->BytesPerPixel); + if(pixel[1]!=0xFF){ + selected=pixel[1]; + retval=true; + } + } + else{ + // Find hotspot represented by widgets + Widget *wptr=spots->GetWidget(X,Y); + if(wptr){ + selected=wptr->GetTag(); + retval=true; + } + } + + return retval; +} + +bool IkuraDisplay::MouseLeftDown(int X,int Y){ + bool retval=false; + if(hitmap){ + // Find hotspots in preloaded hitmap + Uint8 *pixel = static_cast(hitmap->pixels)+ + (Y*hitmap->pitch)+(X*hitmap->format->BytesPerPixel); + if(pixel[1]!=0xFF){ + selected=pixel[1]; + result=selected; + retval=true; + } + } + else{ + // Find hotspot represented by widgets + Widget *wptr=spots->GetWidget(X,Y); + if(wptr){ + selected=wptr->GetTag(); + result=selected; + retval=true; + } + } + return retval; +} + +bool IkuraDisplay::KeyDown(SDLKey Key){ + bool retval=false; + if(KEY_DIRECTION(Key)){ + retval=true; + if(selected<0){ + // Set default key selection + selected=defkey; + Refresh(); + } + else{ + // Map next selection + //keymap.SetUint8(Index,Key,Next); + int s=selected; + switch(Key){ + case SDLK_LEFT: s=keymap.GetUint8(s,2); break; + case SDLK_UP: s=keymap.GetUint8(s,0); break; + case SDLK_RIGHT: s=keymap.GetUint8(s,3); break; + case SDLK_DOWN: s=keymap.GetUint8(s,1); break; + default: break; + } + LogTest("Mapped keyboard %d -> %d",selected,s); + if(s!=selected){ + selected=s; + Refresh(); + } + } + } + else if(KEY_ACTION_OK(Key)){ + if(selected>=0){ + result=selected; + retval=true; + } + } + return retval; +} + +/*! \brief Gets pointer to internal surface + * \param Index Index of internal surface + * \return Pointer to internal surface + * + * Do NOT free the returned surface as it is managed my the display class! + */ +SDL_Surface *IkuraDisplay::GetSurface(int Index){ + SDL_Surface *retval=0; + if(Index>=0 && Index=0){ + DropSpot(Index); + Hotspot *wptr=new Hotspot(); + wptr->Move(X,Y); + wptr->Resize(W,H); + wptr->SetTag(Index); + spots->AddWidget(wptr); + } +} + +void IkuraDisplay::DropSpot(int Index){ + if(Index>=0){ + int cnt=0; + Widget *wptr=spots->GetWidget(cnt++); + while(wptr){ + if(wptr->GetTag()==(unsigned int)Index){ + spots->DestroyWidget(wptr); + break; + } + wptr=spots->GetWidget(cnt++); + } + } +} + +void IkuraDisplay::DropMap(){ + SetMap(NULL); +} + +void IkuraDisplay::Clear(){ + int cnt=0; + Widget *wptr=spots->GetWidget(cnt++); + while(wptr){ + spots->DestroyWidget(wptr); + wptr=spots->GetWidget(cnt++); + } +} + +/*! \brief Loads a named resource into specified buffer + * \param Index Destination buffer index + * \param Resource Graphic resource to load + */ +void IkuraDisplay::SetSurface(int Index,SDL_Surface *Surface){ + if(Index>=0 && Index0 && Indexw,isurface[DIndex]->h}; + if(DRect){ + trect.x=DRect->x; + trect.y=DRect->y; + trect.w=DRect->w; + trect.h=DRect->h; + } + if(isurface[DIndex]->wh %d",SIndex,DIndex); + } +} + +void IkuraDisplay::BlendSurface(int SIndex, + SDL_Rect *SRect,int DIndex,SDL_Rect *DRect){ + if(SIndexw,isurface[DIndex]->h}; + if(DRect){ + trect.x=DRect->x; + trect.y=DRect->y; + trect.w=DRect->w; + trect.h=DRect->h; + } + if(isurface[DIndex]->wh %d",SIndex,DIndex); + } +} + + +/*! \brief Fills a vram surface + * \param Index Destination vram buffer + * \param R Red color value (0-255) + * \param G Green color value (0-255) + * \param B Blue color value (0-255) + */ +void IkuraDisplay::FillSurface(int Index,Uint8 R,Uint8 G,Uint8 B){ + if(Indexw, + isurface[Index]->h,R,G,B,0xFF); + + // Fill display accordingly + if(Index==target){ + Fill(R,G,B,0xFF); + } + } +} + +/* +void IkuraDisplay::ShakeSurface(int Count,int X,int Y,int Duration){ + SDL_Rect srect={0,0,GetWidth(),GetHeight()}; + SDL_Rect erect={X,Y,srect.w,srect.h}; + for(int i=0;i0 && Sourcew,isurface[Source]->h}; + SDL_Rect dst={0,0,isurface[0]->w,isurface[0]->h}; + if(Src){ + src=*Src; + } + if(Dst){ + dst=*Dst; + } + + // Blit and fade + if(isurface[0]){ + EDL_BlitSurface(isurface[Source],&src,isurface[0],&dst); + } + AnimateWidget(new Fade(dst,isurface[Source],src,Duration)); + } +} + +void IkuraDisplay::FadeExternal(SDL_Surface *Source, + SDL_Rect Src,SDL_Rect Dst,int Duration){ + if(isurface[0]){ + EDL_BlitSurface(Source,&Src,isurface[0],&Dst); + } + AnimateWidget(new Fade(Dst,Source,Src,Duration)); +} + */ + + diff --git a/engines/vileVN/ikura/idisplay.h b/engines/vileVN/ikura/idisplay.h new file mode 100644 index 0000000000..f63d5e6619 --- /dev/null +++ b/engines/vileVN/ikura/idisplay.h @@ -0,0 +1,69 @@ +/*! \class IkuraDisplay + * \brief Encapsulates internal graphics handling for ikura games + */ +#ifndef _IDISPLAY_H_ +#define _IDISPLAY_H_ + +#include "../widgets/fade.h" +#include "../widgets/hotspot.h" +#include "../widgets/group.h" + +#define GBSIZE 255 //!< Max index of graphical buffer +#define MBSIZE 32 //!< Size of mouse command buffer + +class IkuraDisplay : public Hotspot { + private: + // Graphic buffers + SDL_Surface *isurface[GBSIZE]; //!< Internally managed graphics + + // Hitmap and hotspot data + SDL_Surface *hitmap; + Group *spots; + DArray keymap; + int defkey; + int selected; + int result; + int target; + public: + IkuraDisplay(int Width,int Height); + IkuraDisplay(SDL_Rect Pos); + ~IkuraDisplay(); + + // Graphics + void SetSurface(int Index,SDL_Surface *Surface); + void SetSurface(int Index,int Width,int Height); + void SetTarget(int Index); + void FillSurface(int SIndex,Uint8 R,Uint8 G,Uint8 B); + SDL_Surface *GetSurface(int Index); + void BlitSurface(int SIndex,SDL_Rect *SRect, + int DIndex,SDL_Rect *DRect); + void BlendSurface(int SIndex,SDL_Rect *SRect, + int DIndex,SDL_Rect *DRect); + + // Hitmap and hotspot data + void SetMap(SDL_Surface *Hitmap); + void SetSpot(int Index,SDL_Rect Area); + void SetSpot(int Index,int X,int Y,int W,int H); + void DropSpot(int Index); + void DropMap(); + void Clear(); + void SetKeyDefault(int Default); + void SetKeyMap(int Index,int Key,int Next); + int GetSelected(bool Unset); + int GetResult(bool Unset); + + // Hook into user input + virtual bool FocusEnter(); + virtual bool FocusLeave(); + virtual bool TestMouse(int X,int Y); + virtual bool MouseMove(int X,int Y); + virtual bool MouseLeftDown(int X,int Y); + virtual bool KeyDown(SDLKey Key); + + // Export savegame data + bool Save(Savegame *File); + bool Load(Savegame *File); +}; + +#endif + diff --git a/engines/vileVN/ikura/idols/idols.cpp b/engines/vileVN/ikura/idols/idols.cpp new file mode 100644 index 0000000000..0a9c98057c --- /dev/null +++ b/engines/vileVN/ikura/idols/idols.cpp @@ -0,0 +1,81 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "idols.h" + +Idols::Idols(uString Path) : IkuraDecoder(640,480){ + // Load resources + AddScripts(new ArchiveIkura(Path+"ISF")); + AddImages(new ArchiveIkura(Path+"GGD")); + AddVoices(new ArchiveIkura(Path+"VOICE")); + AddSE(new ArchiveIkura(Path+"SE")); + AddBGM(new ArchiveIkura(Path+"WMSC")); + AddBGM(new ArchiveIkura(Path+"MIDI")); + AddVideo(new ArchiveFiles(Path+"SEKIRA64.avi")); + AddOther(new ArchiveIkura(Path+"DATA")); + CreateTextview(); + + // Load standard boot script + RunScript("START.ISF"); +} + +const uString Idols::NativeID(){ + return "IDOLS"; +} + +const uString Idols::NativeName(){ + return "Idols Galore!"; +} + +void Idols::CreateTextview(){ + // Load textwindow graphic and prepare widget + w_textview->SetTextPosition(25,45,585,85); + SDL_Surface *tmpsurface=LoadImage("M_WIN.GGP"); + + if(tmpsurface){ + // Set window graphics + w_textview->Resize(tmpsurface->w,tmpsurface->h); + w_textview->Set(tmpsurface); + + // Clean up temporary surface + SDL_FreeSurface(tmpsurface); + } + else{ + LogError("Failed to load textview graphics"); + } +} + +/*TODO: + Handle some new text situations in the IkuraDecoder class iop_pm: + + "2B 17 00 03 01 00 FF 92 BE 01 01 5A 00 13 04 01 00 01 00 FF FF FF 00" + ends up spitting out 0x64 "Z" character and gives an error for an invalid + sound resource 0x03. I'm not really sure what this is intended to do yet. + It could have something to do with Kyoka's name displaying in pink? The "Z" + character always shows up right before she speaks. It seems to also appear + before Megumi (name in blue) or Aya (name in pink) speak, so that guess + seems pretty likely. Voices aren't working either, and this is probably + related. + + Perhaps look at opcode 0x6F usage. It doesn't seem important, but who knows? + + Character names are not being printed. Since they aren't using images, + they don't "just work" like they have in other games. + + The game plays pretty well. I'll save fixing the text problems mentioned + above for someone else, as my attempts at tweaking the iop_pm function and + understanding intended behavior have proven frustrating. + */ + diff --git a/engines/vileVN/ikura/idols/idols.h b/engines/vileVN/ikura/idols/idols.h new file mode 100644 index 0000000000..798bf90ec9 --- /dev/null +++ b/engines/vileVN/ikura/idols/idols.h @@ -0,0 +1,22 @@ +/*! \class Idols + * \brief Loader class for Idols Galore! + */ +#ifndef _IDOLS_H_ +#define _IDOLS_H_ + +#include "../ikuradecoder.h" + +class Idols : public IkuraDecoder { + private: + // Override game attributes + const uString NativeID(); + const uString NativeName(); + + // Macro for fancy textview + void CreateTextview(); + public: + Idols(uString Path); +}; + +#endif + diff --git a/engines/vileVN/ikura/ikuradecoder.cpp b/engines/vileVN/ikura/ikuradecoder.cpp new file mode 100644 index 0000000000..06682b3668 --- /dev/null +++ b/engines/vileVN/ikura/ikuradecoder.cpp @@ -0,0 +1,2045 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "ikuradecoder.h" + +IkuraDecoder::IkuraDecoder(int Width,int Height) : EngineVN(Width,Height){ + // Preset values + state=IS_NORMAL; + asurfaces=0; + isf_keybuffer=0; + isf_keysize=0; + selresult=-1; + + // Create ikura widget + SDL_Rect bgrect={0,0,Width,Height}; + w_display=new IkuraDisplay(bgrect); + AddWidget(w_display,VL_BACKGROUND); + + // Create base widgets + w_textview=new Textview(this); + w_select=new Selection(this); + AddWidget(w_textview,VL_TEXTVIEW); + AddWidget(w_select,VL_CHOICES); + + // Configure default w_textview (Crescendo style) + w_textview->SetVisible(false); + w_textview->Resize(640,480); + w_textview->SetTextPosition(20,20,600,460); + w_textview->Fill(0,0,0,128); + + // Configure default selection (Crescendo style) + w_select->SetVisible(false); + w_select->Resize(640,480); + w_select->SetColors(0x00000000,0x000000FF,0x00000000,0xFFFFFFFF); + w_select->SetFontSize(26); + + // Load encryption key + if(Cfg::System::Keyfile.length()>0){ + RWops ops; + LogVerbose("Loading key file: %s",Cfg::System::Keyfile.c_str()); + if(ops.OpenFile(Cfg::System::Keyfile.c_str(),"rb")){ + isf_keysize=ops.Size(); + if(isf_keysize>0){ + isf_keybuffer=new char[isf_keysize]; + ops.Read(isf_keybuffer,isf_keysize); + } + } + else{ + LogError("Failed to open key: %s",Cfg::System::Keyfile.c_str()); + } + } +} + +IkuraDecoder::~IkuraDecoder(){ + if(asurfaces){ + for(int i=0;asurfaces[i];i++){ + SDL_FreeSurface(asurfaces[i]); + } + delete asurfaces; + } + if(isf_keybuffer){ + delete [] isf_keybuffer; + } +} + +void IkuraDecoder::SetKey(char *Buffer,int Size){ + if(isf_keybuffer){ + delete [] isf_keybuffer; + } + isf_keysize=Size; + isf_keybuffer=new char[Size]; + strncpy(isf_keybuffer,Buffer,Size); +} + +void IkuraDecoder::DecodeScript(Uint8 *Buffer,int Size){ + if(Size>16 && !strncmp((char*)Buffer+Size-16,"SECRETFILTER100a",16)){ + if(isf_keybuffer && isf_keysize){ + Size-=16; + int cycles=(Size/isf_keysize)+1; + LogDebug("Decoding %d bytes ISF data in %d cycles",Size,cycles); + for(int i=0;iSeek(0,SEEK_END); + if(tlength>(int)0){ + blob->Seek(0,SEEK_SET); + Uint8 *tbuffer=new Uint8[tlength]; + if(blob->Read(tbuffer,tlength)>(int)0){ + // Load script data + DecodeScript(tbuffer,tlength); + retval=parser.LoadScript(Name.c_str(),tbuffer,tlength,0); + state=IS_NORMAL; + } + delete [] tbuffer; + } + delete blob; + } + else{ + LogError("Failed to load %s",Name.c_str()); + } + return retval; +} + +void IkuraDecoder::EventGameDialog(VN_DIALOGS Dialog){ + if(Dialog==VD_TITLE){ + RWops *blob=0; + if((blob=LoadScript("TITLE","ISF"))){ + int tlength=blob->Seek(0,SEEK_END); + if(tlength>(int)0){ + blob->Seek(0,SEEK_SET); + Uint8 *tbuffer=new Uint8[tlength]; + if(blob->Read(tbuffer,tlength)>(int)0){ + DecodeScript(tbuffer,tlength); + parser.LoadScript("TITLE",tbuffer,tlength,0); + state=IS_NORMAL; + } + delete [] tbuffer; + } + delete blob; + } + } + else{ + EngineVN::EventGameDialog(Dialog); + } +} + +bool IkuraDecoder::EventBackgroundMouseRightDown(int X,int Y){ + w_textview->SetVisible(!w_textview->GetVisible()); + return true; +} + +void IkuraDecoder::EventSelect(int Selection){ + selresult=Selection; +} + +bool IkuraDecoder::EventLoad(int Index){ + Savegame *load=new Savegame(NativeID(),Index); + if(load->Read()){ + if(!parser.Load(this,load)){ + LogError("Parser refused savegame input"); + } + else if(!w_display->Load(load)){ + LogError("Display module refused savegame input"); + } + else{ + if(w_select){ + w_select->SetVisible(false); + } + if(w_textview){ + w_textview->ClearText(); + } + LogVerbose("Loaded savegame"); + } + state=IS_NORMAL; + } + delete load; + return true; +} + +/*! \brief Handles save events + * \param Index Internal savegame index + * \return True + */ +bool IkuraDecoder::EventSave(int Index){ + Savegame *save=new Savegame(NativeID(),Index); + if(!parser.Save(save)){ + LogError("Parser refused savegame request"); + } + else if(!w_display->Save(save)){ + LogError("Display module refused savegame request"); + } + else{ + // Gather date string and save metadata + uString date=EDL_DateString(EDL_UnixTime()); + uString time=EDL_TimeString(EDL_UnixTime()); + uString datetime=date+uString(" ")+time; + save->SaveString("savedate",datetime); + save->SaveString("savemsg",GetSavename()); + + // Store graphics onscreen graphics + SDL_Surface *screen=EDL_CreateSurface(NativeWidth(),NativeHeight()); + Paint(screen,VL_CHOICES); + save->SaveSurface("screen-thumb",screen,96,72); + + // Write savegame to disk + save->Write(); + } + delete save; + return true; +} + +bool IkuraDecoder::EventGameTick(){ + if(state==IS_WAITTIMER){ + if(timerendCompleteText(); + while(SkipAnimation()); + state=IS_NORMAL; + } + } + if(state==IS_WAITTEXT){ + if(!w_textview->GetRemainingText()){ + // Printing has completed + state=IS_NORMAL; + } + else if(keyctrl()){ + // Skip state and fall back + w_textview->CompleteText(); + while(SkipAnimation()); + state=IS_NORMAL; + } + else if(keyok){ + // Complete printing text + w_textview->CompleteText(); + keyok=false; + } + } + if(state==IS_WAITCLICK){ + if(keyctrl()){ + // Skip state and fall back + w_textview->CompleteText(); + while(SkipAnimation()); + state=IS_NORMAL; + } + else if(keyok){ + // Advance text + if(!w_textview->GetRemainingText()){ + state=IS_NORMAL; + } + w_textview->CompleteText(); + while(SkipAnimation()); + } + } + return !(state==IS_NORMAL); +} + + +/*! \brief Advances the scripted engine + * \returns True if the engine is waiting for user input + */ +bool IkuraDecoder::EventGameProcess(){ + Uint8 c; + Uint32 l; + const Uint8 *b; + bool r=true; + if(parser.GetOpcode(&c,&b,&l)){ + switch(c){ + case IOP_CALC: r=iop_calc(b,l); break; + case IOP_IM: r=iop_im(b,l); break; + case IOP_IF: r=iop_if(b,l); break; + case IOP_RT: r=iop_rt(b,l); break; + case IOP_SET: r=iop_set(b,l); break; + case IOP_SEP: r=iop_sep(b,l); break; + case IOP_SER: r=iop_ser(b,l); break; + case IOP_GN: r=iop_gn(b,l); break; + case IOP_GC: r=iop_gc(b,l); break; + case IOP_GL: r=iop_gl(b,l); break; + case IOP_GO: r=iop_go(b,l); break; + case IOP_GGE: r=iop_gge(b,l); break; + case IOP_VSET: r=iop_vset(b,l); break; + case IOP_GV: r=iop_gv(b,l); break; + case IOP_GP: r=iop_gp(b,l); break; + case IOP_JP: r=iop_jp(b,l); break; + case IOP_JS: r=iop_js(b,l); break; + case IOP_ONJP: r=iop_onjp(b,l); break; + case IOP_ONJS: r=iop_onjs(b,l); break; + case IOP_SSP: r=iop_ssp(b,l); break; + case IOP_SCP: r=iop_scp(b,l); break; + case IOP_WS: r=iop_ws(b,l); break; + case IOP_WP: r=iop_wp(b,l); break; + case IOP_WSS: r=iop_wss(b,l); break; + case IOP_WSH: r=iop_wsh(b,l); break; + case IOP_PPF: r=iop_ppf(b,l); break; + case IOP_DAS: r=iop_das(b,l); break; + case IOP_DAP: r=iop_dap(b,l); break; + case IOP_PM: r=iop_pm(b,l); break; + case IOP_PF: r=iop_pf(b,l); break; + case IOP_MS: r=iop_ms(b,l); break; + case IOP_ML: r=iop_ml(b,l); break; + case IOP_SES: r=iop_ses(b,l); break; + case IOP_PCMS: r=iop_pcms(b,l); break; + case IOP_PCML: r=iop_pcml(b,l); break; + case IOP_PCMON: r=iop_pcmon(b,l); break; + case IOP_CSET: r=iop_cset(b,l); break; + case IOP_CP: r=iop_cp(b,l); break; + case IOP_CW: r=iop_cw(b,l); break; + case IOP_CWO: r=iop_cwo(b,l); break; + case IOP_CWC: r=iop_cwc(b,l); break; + case IOP_WC: r=iop_wc(b,l); break; + case IOP_WO: r=iop_wo(b,l); break; + case IOP_CC: r=iop_cc(b,l); break; + case IOP_EXC: r=iop_exc(b,l); break; + case IOP_EXS: r=iop_exs(b,l); break; + case IOP_STS: r=iop_sts(b,l); break; + case IOP_IGINIT: r=iop_iginit(b,l); break; + case IOP_IGRELEASE: r=iop_igrelease(b,l); break; + case IOP_STX: r=iop_stx(b,l); break; + case IOP_HDEC: r=iop_hdec(b,l); break; + case IOP_HINC: r=iop_hinc(b,l); break; + case IOP_TITLE: r=iop_title(b,l); break; + case IOP_SETGAMEINFO: r=iop_setgameinfo(b,l); break; + case IOP_CNS: r=iop_cns(b,l); break; + case IOP_UDDA: r=iop_udda(b,l); break; + case IOP_VOC: r=iop_voc(b,l); break; + + // Flag related + case IOP_HS: r=iop_hs(b,l); break; + case IOP_HSG: r=iop_hsg(b,l); break; + case IOP_HT: r=iop_ht(b,l); break; + case IOP_HP: r=iop_hp(b,l); break; + case IOP_HXP: r=iop_hxp(b,l); break; + case IOP_HF: r=iop_hf(b,l); break; + case IOP_SP: r=iop_sp(b,l); break; + case IOP_SK: r=iop_sk(b,l); break; + case IOP_SKS: r=iop_sks(b,l); break; + case IOP_HN: r=iop_hn(b,l); break; + case IOP_EC: r=iop_ec(b,l); break; + case IOP_ES: r=iop_es(b,l); break; + case IOP_FT: r=iop_ft(b,l); break; + + // Forced wait states + case IOP_CLK: r=iop_clk(b,l); break; + + // Input definitions + case IOP_IG: r=iop_ig(b,l); break; + case IOP_IH: r=iop_ih(b,l); break; + case IOP_IHGP: r=iop_ihgp(b,l); break; + case IOP_IHGC: r=iop_ihgc(b,l); break; + case IOP_IHGL: r=iop_ihgl(b,l); break; + case IOP_IHK: r=iop_ihk(b,l); break; + case IOP_IHKDEF: r=iop_ihkdef(b,l); break; + + // Script loading + case IOP_LS: r=iop_ls(b,l); break; + case IOP_LSBS: r=iop_lsbs(b,l); break; + case IOP_SRET: r=iop_sret(b,l); break; + + // Timerstuff + case IOP_ATIMES: r=iop_atimes(b,l); break; + case IOP_AWAIT: r=iop_await(b,l); break; + case IOP_TIMERGET: r=iop_timerget(b,l); break; + case IOP_TIMERSET: r=iop_timerset(b,l); break; + case IOP_TIMEREND: break; + + // Loading and saving + case IOP_OPSL: r=iop_opsl(b,l); break; + case IOP_SVF: r=iop_svf(b,l); break; + + // Option dialogue + case IOP_OPPROP: r=iop_opprop(b,l); break; + case IOP_ENABLE: r=iop_enable(b,l); break; + case IOP_DISABLE: r=iop_disable(b,l); break; + case IOP_SLDRSET: r=iop_sldrset(b,l); break; + case IOP_CBSET: r=iop_cbset(b,l); break; + case IOP_RBSET: r=iop_rbset(b,l); break; + case IOP_TAGSET: r=iop_tagset(b,l); break; + case IOP_FRAMESET: r=iop_frameset(b,l); break; + + // Animations + case IOP_GAOPEN: r=iop_gaopen(b,l); break; + case IOP_GASTART: r=iop_gastart(b,l); break; + case IOP_AVIP: r=iop_avip(b,l); break; + + // Font and text control + case IOP_SETFONTCOLOR: r=iop_setfontcolor(b,l); break; + case IOP_SETFONTSTYLE: r=iop_setfontstyle(b,l); break; + case IOP_PB: r=iop_pb(b,l); break; + case IOP_GPB: r=iop_gpb(b,l); break; + + // Shut down engine + case IOP_ED: r=iop_ed(b,l); break; + + // Undocumented opcodes + case IOP_UDAE: r=iop_udae(b,l); break; + case IOP_UDAF: r=iop_udaf(b,l); break; + + // Misc unsupported opcodes + //case IOP_HLN: // Set number of variables + //case IOP_FLN: // Set number of flags + //case IOP_EXA: // Space for extra variables + //case IOP_CPS: // Set character palette + + // Media stuff + case IOP_MP: // Play music (Played upon load) + case IOP_MF: // Fade music + case IOP_PCMCN: // Cache sound + case IOP_GASTOP: // Stop animation + case IOP_GACLOSE: // Close animation + case IOP_GADELETE: // Delete animation + + // Text management + case IOP_KIDFN: // Number of lines (Read-flags) + case IOP_KIDMOJI: // Set "read text" font color + case IOP_KIDSCAN: // Check wether line has been read + case IOP_KIDCLR: // Clear read flags? + + // Cursor control + case IOP_IC: // Change cursor + case IOP_CLKEXMCSET: // Set "waiting" cursor + + break; + default: r=iop_unknown(c,b,l); break; + } + } + return r; +} + +bool IkuraDecoder::iop_check(int ExpectedLength, + const Uint8 Code,const Uint8 *Data,int Length){ + if(ExpectedLength==Length){ + return true; + } + else{ + LogError("Expected %d (not %d!) bytes for %x:", + ExpectedLength,Length,Code); + for(int i=0;iResize(tmpsurface->w,tmpsurface->h); + w_textview->Set(tmpsurface); + } + SDL_FreeSurface(tmpsurface); + cnt++; + } + while(iMoveDialog(x,y); + if(w && h){ + w_textview->Resize(w,h); + } + } + return false; +} + +// Hide text window +bool IkuraDecoder::iop_wsh(const Uint8 *Data,int Length){ + if(iop_check(4,IOP_WSH,Data,Length)){ + LogDebug("Hide text window:%d",parser.DecodeValue(GETDWORD(Data))); + w_textview->SetVisible(false); + } + return false; +} + +// Show text window +bool IkuraDecoder::iop_wss(const Uint8 *Data,int Length){ + // Set text window dimensions + if(iop_check(4,IOP_WSS,Data,Length)){ + LogDebug("Show text window:%d",parser.DecodeValue(GETDWORD(Data))); + w_textview->SetVisible(true); + } + return false; +} + +// Possibly textual commands to the windows mci api +bool IkuraDecoder::iop_im(const Uint8 *Data,int Length){ + LogDebug("IM:%d:%s",Data[0],Data+1); + return false; +} + +// IF-THEN logic block (May be nested!) +bool IkuraDecoder::iop_if(const Uint8 *Data,int Length){ + bool result=true; + for(int i=0;result && iv2); break; + case 0x04: result=(v1>=v2); break; + case 0x05: result=(v1!=v2); break; + default: result=false; break; + } + + // Check next operation + o=GETBYTE(Data+i+9); + if(!result){ + // Dont process any further .. + } + else if(o==0x00){ + // Get jumptable ref + parser.JumpFunction(GETWORD(Data+i+10)); + result=false; + } + else if(o==0x01){ + // Set variable + Uint16 dst=GETWORD(Data+i+10); + int val=parser.DecodeValue(GETDWORD(Data+i+12)); + parser.SetValue(dst,val); + result=false; + } + else if(o==0x02){ + // AND next operation ... + } + else if(o==0xFF){ + // End if + result=false; + } + else{ + LogError("UNKNOWN IF THEN OPERATOR: %x",o); + } + } + return false; +} + +// Decrements a register value +bool IkuraDecoder::iop_hdec(const Uint8 *Data,int Length){ + if(iop_check(2,IOP_HDEC,Data,Length)){ + Uint16 dest=GETWORD(Data); + parser.SetValue(dest,parser.GetValue(dest)-1); + } + return false; +} + +// Increments a register value +bool IkuraDecoder::iop_hinc(const Uint8 *Data,int Length){ + if(iop_check(2,IOP_HINC,Data,Length)){ + Uint16 dest=GETWORD(Data); + parser.SetValue(dest,parser.GetValue(dest)+1); + } + return false; +} + +// Set group of variables (Like a for-loop) +bool IkuraDecoder::iop_hsg(const Uint8 *Data,int Length){ + if(iop_check(8,IOP_HSG,Data,Length)){ + // Extract iteration data + Uint16 start=GETWORD(Data); + Uint16 end=GETWORD(Data+2); + int value=parser.DecodeValue(GETDWORD(Data+4)); + + // Set group of variables + for(int i=start;i %d",start,end); + return false; +} + +// Save system flag flags (Ignored ... handled internally in ViLE) +bool IkuraDecoder::iop_es(const Uint8 *Data,int Length){ + LogTest("Save system flags: %d",parser.DecodeValue(GETDWORD(Data))); + return false; +} + +// Transfer flags +bool IkuraDecoder::iop_ft(const Uint8 *Data,int Length){ + LogTest("UNHANDLED FT FLAGS: %d",Length); + return false; +} + +// Jump if flags[dst]==0? (3B) +bool IkuraDecoder::iop_hn(const Uint8 *Data,int Length){ + if(iop_check(4,IOP_HN,Data,Length)){ + Uint8 value=parser.GetFlag(GETWORD(Data)); + Uint16 entry=GETWORD(Data+2); + if(!value){ + parser.JumpFunction(entry); + } + } + return false; +} + +// Set flag pattern (35) +// +// Seems to set variable depending on read flags: +// SP 1,(106,107,108,109) +// +// Flags can be expanded like below, destination does not seem to be +// a flag and can be read by the hp opcode +bool IkuraDecoder::iop_sp(const Uint8 *Data,int Length){ + Uint8 dst=Data[0]; + Uint8 *buffer=new Uint8[Length-1]; + for(int i=1;iSetTextInterval(val); + } + else{ + LogError("OTHER WINDOWS NOT SUPPORTED: %d",dst); + } + } + return false; +} + +// Print text messages +bool IkuraDecoder::iop_pm(const Uint8 *Data,int Length){ +/* +char b[255]; +uString sc,sx; +for(int i=1;iClearText(); + } + else if(cmd==0x01 && Data[i]==0x00){ + // Specify color inline + Uint8 r=Data[++i]; + Uint8 g=Data[++i]; + Uint8 b=Data[++i]; + w_textview->SetFontColor(r,g,b); + i++; + } + else if(cmd==0x01 && Data[i]==0x01){ + // ??? + //Uint16 x=GETWORD(Data+i+1); + //LogTest("PM:0101:%d",x); + i+=2; + } + else if(cmd==0x04){ + // ??? + //Uint8 x=GETBYTE(Data+i); + //LogTest("PM:04:%d",x); + i++; + } + else if(cmd==0x06){ + // ??? + } + else if(cmd==0x08){ + // Previously read + //int linenumber=parser.DecodeValue(GETDWORD(Data+i)); + //LogVerbose("PM:%d (Previously read)",linenumber); + i+=4; + } + else if(cmd==0x11){ + // Name of talking character + char tbuf[32]; + int name=parser.DecodeValue(GETDWORD(Data+i)); + sprintf(tbuf,"FW%3.3d",name); + SDL_Surface *tmpsurface=LoadImage(tbuf); + if(tmpsurface){ + w_textview->Blit(tmpsurface); + SDL_FreeSurface(tmpsurface); + } + i+=4; + } + else if(cmd==0x13){ + if(Data[i]>0x1F){ + // Play associated voice file + PlayVoice((char*)Data+i); + while(iPrintText(name); + w_textview->CompleteText(); + } + i+=3; + } + else{ + LogError("Unknown voice command: 0x%02X",Data[i]); + } + } + else if(cmd==0xFF){ + // Print text + uString text; + for(;Data[i];i++){ + if(Data[i]<0x7F && Data[i]>0x1F){ + text+=(char)Data[i]; + } + } + w_textview->SetVisible(true); + w_textview->PrintNewline(); + w_textview->PrintText(text.c_str()); + + // Change state + state=IS_WAITTEXT; + } + else if(cmd){ + LogVerbose("Unknown inline command: 0x%02X",cmd); + } + } + return true; +} + +// Stop music +bool IkuraDecoder::iop_ms(const Uint8 *Data,int Length){ + StopMusic(); + return false; +} + +// Load music track +bool IkuraDecoder::iop_ml(const Uint8 *Data,int Length){ + //Uint8 par=Data[Length-1]; + PlayMusic((char*)Data); + return false; +} + +// Stop CDDA music +bool IkuraDecoder::iop_das(const Uint8 *Data,int Length){ + StopMusic(); + return false; +} + +// Load CDDA music track +bool IkuraDecoder::iop_dap(const Uint8 *Data,int Length){ + int channel=parser.DecodeValue(GETDWORD(Data)); + if(!PlayMusic(EDL_Format("TK%02d",channel))){ + if(!PlayMusic(EDL_Format("TK_%02d",channel))){ + if(!PlayMusic(EDL_Format("TK-%02d",channel))){ + LogError("CDDA playback not supported!"); + } + } + } + + PlayMusic((char*)Data); + return false; +} + +// Stop sound effect +bool IkuraDecoder::iop_ses(const Uint8 *Data,int Length){ + if(iop_check(8,IOP_SES,Data,Length)){ + int channel=parser.DecodeValue(GETDWORD(Data)); + //int duration=parser.DecodeValue(GETDWORD(Data+4)); + StopSound(channel); + } + return false; +} + +// Play PCM (voice) +bool IkuraDecoder::iop_pcmon(const Uint8 *Data,int Length){ + return false; +} + +// Stop PCM (voice) +bool IkuraDecoder::iop_pcms(const Uint8 *Data,int Length){ + StopSound(VA_VOICES); + return false; +} + +// Load PCM (voice) +bool IkuraDecoder::iop_pcml(const Uint8 *Data,int Length){ + PlayVoice((char*)Data,VA_VOICES); + return false; +} + +// Return from subscript +bool IkuraDecoder::iop_sret(const Uint8 *Data,int Length){ + parser.ReturnScript(); + return false; +} + +// Call a subscript +bool IkuraDecoder::iop_lsbs(const Uint8 *Data,int Length){ + RWops *blob=0; + if((blob=LoadScript((char*)Data,"ISF"))){ + int tlength=blob->Seek(0,SEEK_END); + if(tlength>(int)0){ + blob->Seek(0,SEEK_SET); + Uint8 *tbuffer=new Uint8[tlength]; + if(blob->Read(tbuffer,tlength)>(int)0){ + // Load script and CALL it + DecodeScript(tbuffer,tlength); + parser.CallScript((char*)Data,tbuffer,tlength); + } + delete [] tbuffer; + } + delete blob; + } + return false; +} + +// Loads a new script +bool IkuraDecoder::iop_ls(const Uint8 *Data,int Length){ + RWops *blob=0; + if((blob=LoadScript((char*)Data,"ISF"))){ + int tlength=blob->Seek(0,SEEK_END); + if(tlength>(int)0){ + blob->Seek(0,SEEK_SET); + Uint8 *tbuffer=new Uint8[tlength]; + if(blob->Read(tbuffer,tlength)>(int)0){ + // Load script and JMP to it + DecodeScript(tbuffer,tlength); + parser.JumpScript((char*)Data,tbuffer,tlength); + } + delete [] tbuffer; + } + delete blob; + } + return false; +} + +// Sets window caption +bool IkuraDecoder::iop_title(const Uint8 *Data,int Length){ + uString t="ViLE: "; + t+=(char*)Data; + LogDebug("Setting title: %s",t.c_str()); + SDL_WM_SetCaption(t.c_str(),t.c_str()); + return false; +} + +// Sets a name for the savegame +bool IkuraDecoder::iop_setgameinfo(const Uint8 *Data,int Length){ + SetSavename((char*)Data); + return false; +} + +// Store character names +bool IkuraDecoder::iop_cns(const Uint8 *Data,int Length){ + //Uint8 par1=Data[0]; + Uint8 index=Data[1]; + char name[Length]; + strncpy(name,(char*)Data+2,Length-2); + name[Length-2]=0; + s_names.SetString(index,name); + LogVerbose("Registering character name %d=%s",index,name); + return false; +} + +// Voice file registration (For enabling disabling individual voices) +bool IkuraDecoder::iop_voc(const Uint8 *Data,int Length){ + Uint32 value1=parser.DecodeValue(GETDWORD(Data)); + Uint16 value2=GETWORD(Data+4); + uString voc=(char*)Data+6; + LogVerbose("Registering voice file %d %d:%s",value1,value2,voc.c_str()); + return false; +} + +// Registers number of voicefile types +bool IkuraDecoder::iop_udda(const Uint8 *Data,int Length){ + Uint32 value=parser.DecodeValue(GETDWORD(Data)); + LogVerbose("Voicefile registrations:%d",value); + return false; +} + +bool IkuraDecoder::iop_clk(const Uint8 *Data,int Length){ + state=IS_WAITCLICK; + return true; +} + +bool IkuraDecoder::iop_cp(const Uint8 *Data,int Length){ + LogTest("Loading command window:%s",Data); + return false; +} + +// Close command screen +bool IkuraDecoder::iop_cwc(const Uint8 *Data,int Length){ + LogTest("Closing Command window: %d",Data[0]); + w_textview->SetVisible(false); + return false; +} + +// Set command window position +bool IkuraDecoder::iop_cw(const Uint8 *Data,int Length){ + Uint8 dst=GETBYTE(Data); + Uint32 x=GETDWORD(Data+1); + Uint32 y=GETDWORD(Data+5); + Uint32 w=GETDWORD(Data+9); + Uint32 h=GETDWORD(Data+13); + Uint8 cmd=GETBYTE(Data+17); + if(dst){ + LogError("ILLEGAL COMMAND WINDOW:%d",dst); + } + LogVerbose("Command window position:%d,%d,%d,%d,%d,%d",dst,x,y,w,h,cmd); + return false; +} + +// Open command screen +// par1 might have something to do with a destination +// par2 might be number of options +bool IkuraDecoder::iop_cwo(const Uint8 *Data,int Length){ + // Decode parameters + Uint8 par1=GETBYTE(Data+0); + Uint8 par3=GETBYTE(Data+5); + int cnt=parser.DecodeValue(GETDWORD(Data+1)); + LogTest("Opening Command selection: %d,%d,%d",par1,cnt,par3); + if(w_select){ + w_select->SetVisible(true); + selresult=-1; + } + return true; +} + +// Execute command selection +bool IkuraDecoder::iop_cc(const Uint8 *Data,int Length){ + if(iop_check(4,IOP_CC,Data,Length)){ + // Parse values + LogTest("CC:%x:%x:%x:%x",Data[0],Data[1],Data[2],Data[3]); + Uint8 par1=Data[0]; + Uint8 dst=Data[1]; + Uint8 par2=Data[2]; + Uint8 cmd=Data[3]; + + // Interpret command field + + if(!w_select){ + LogError("Invalid selection control"); + } + else if(cmd==0x01){ + // Set default value for target register + parser.SetValue(dst,-1); + } + else if(cmd==0x02){ + // Closing command selection + w_select->SetVisible(false); + w_select->Clear(); + } + else if(cmd==0x03){ + // Get command status + if(selresult>=0){ + parser.SetValue(dst,selresult); + } + } + else{ + LogError("Unknown selection command:%d (%d,%d)",cmd,par1,par2); + } + } + return false; +} + +// Configures a command option +bool IkuraDecoder::iop_cset(const Uint8 *Data,int Length){ + Uint8 dst=GETBYTE(Data); // Where to place the result + Uint8 val=GETBYTE(Data+1); // Identifying value + Uint32 x=GETDWORD(Data+2); + Uint32 y=GETDWORD(Data+6); + Uint32 w=GETDWORD(Data+10); + Uint32 h=GETDWORD(Data+14); + + // Check destination + if(dst){ + LogError("Unexpected CSET destination:%d",dst); + } + + // Extract and terminate caption + char caption[Length-18]; + strncpy(caption,(char*)Data+18,Length-18); + caption[Length-18]=0; + + // Create a new command option + SDL_Rect rect={x,y,w,h}; + if(w_select){ + w_select->SetText(caption,rect,val); + } + + return false; +} + +// Set font color +bool IkuraDecoder::iop_setfontcolor(const Uint8 *Data,int Length){ + if(Length==5){ + if(iop_check(5,IOP_SETFONTCOLOR,Data,Length)){ + Uint8 window=GETBYTE(Data+0); + Uint8 font=GETBYTE(Data+1); + Uint8 r=GETBYTE(Data+2); + Uint8 g=GETBYTE(Data+3); + Uint8 b=GETBYTE(Data+4); + if(window==0 && font==0){ + w_textview->SetFontColor(r,g,b); + } + } + } + // Found colors stored as DWORDs in Cat Girl Alliance + else if(Length==14){ + if(iop_check(14,IOP_SETFONTCOLOR,Data,Length)){ + Uint8 window=GETBYTE(Data+0); + Uint8 font=GETBYTE(Data+1); + int r=parser.DecodeValue(GETDWORD(Data+2)); + int g=parser.DecodeValue(GETDWORD(Data+6)); + int b=parser.DecodeValue(GETDWORD(Data+10)); + if(window==0 && font==0){ + w_textview->SetFontColor(r,g,b); + } + } + } + return false; +} + +// Set font style +bool IkuraDecoder::iop_setfontstyle(const Uint8 *Data,int Length){ + if(iop_check(2,IOP_SETFONTSTYLE,Data,Length)){ + Uint8 window=GETBYTE(Data); + Uint8 style=GETBYTE(Data+1); + if(window==0){ + // Set native styles + int ttfstyle=0; + if(style&IKURA_FONTSTYLE_BOLD){ + ttfstyle|=TTF_STYLE_BOLD; + } + if(style&IKURA_FONTSTYLE_ITALIC){ + ttfstyle|=TTF_STYLE_BOLD; + } + w_textview->SetFontStyle(ttfstyle); + + // Enable effects + SDL_Color c={0,0,0}; + if(style&IKURA_FONTSTYLE_MASK){ + w_textview->SetFontShadow(2,2,c); + } + if(style&IKURA_FONTSTYLE_SHADOW){ + w_textview->SetFontShadow(2,2,c); + } + } + } + return false; +} + +// Set font size +bool IkuraDecoder::iop_pb(const Uint8 *Data,int Length){ + if(iop_check(5,IOP_PB,Data,Length)){ + Uint8 window=GETBYTE(Data); + int size=parser.DecodeValue(GETDWORD(Data+1)); + if(window==0){ + w_textview->SetFontSize(size); + } + } + return false; +} + +// Set text size +bool IkuraDecoder::iop_gpb(const Uint8 *Data,int Length){ + if(iop_check(4,IOP_GPB,Data,Length)){ + int size=parser.DecodeValue(GETDWORD(Data)); + w_textview->SetFontSize(size); + } + return false; +} + +// Return from subroute +bool IkuraDecoder::iop_rt(const Uint8 *Data,int Length){ + parser.ReturnFunction(); + return false; +} + +bool IkuraDecoder::iop_set(const Uint8 *Data,int Length){ + if(iop_check(4,IOP_SET,Data,Length)){ + int channel=parser.DecodeValue(GETDWORD(Data)); + StopSound(channel); + } + return false; +} + +bool IkuraDecoder::iop_sep(const Uint8 *Data,int Length){ + //int channel=parser.DecodeValue(GETDWORD(Data)); + //int tick=0; + if(Length==8){ + // Extra duration parameter + //tick=parser.DecodeValue(GETDWORD(Data+4)); + } + return false; +} + +// Play sound +bool IkuraDecoder::iop_ser(const Uint8 *Data,int Length){ + // A register with the channel to use is also passed, + // but we dont deal with channels and ignore it. + int channel=parser.DecodeValue(GETDWORD(Data+Length-4)); + PlaySound((char*)Data,channel); + return false; +} + +// Initialize surfaces +bool IkuraDecoder::iop_vset(const Uint8 *Data,int Length){ + if(iop_check(12,IOP_VSET,Data,Length)){ + int dst=parser.DecodeValue(GETDWORD(Data+0)); + int w=parser.DecodeValue(GETDWORD(Data+4)); + int h=parser.DecodeValue(GETDWORD(Data+8)); + w_display->SetSurface(dst,w,h); + } + return false; +} + +// Effects using grayscale (Not fully supported) +bool IkuraDecoder::iop_gge(const Uint8 *Data,int Length){ + //int type=parser.DecodeValue(GETDWORD(Data+0)); + int num=parser.DecodeValue(GETDWORD(Data+4)); + int tick=parser.DecodeValue(GETDWORD(Data+8)); + //int dir=parser.DecodeValue(GETDWORD(Data+12)); + //int len=parser.DecodeValue(GETDWORD(Data+16)); + //char *name=(char*)Data+20; + + // No support for effect files (yet) + w_display->BlitSurface(num,0,0,0); + SDL_Surface *surface=w_display->GetSurface(num); + if(surface){ + SDL_Rect r={0,0,surface->w,surface->h}; + AddAnimation(new Fade(r,surface,r,tick)); + } + return true; +} + +// Shaking effect +bool IkuraDecoder::iop_gv(const Uint8 *Data,int Length){ + if(iop_check(8,IOP_GV,Data,Length)){ + // Parse parameters + Uint16 count=GETWORD(Data); + Uint8 x=GETBYTE(Data+2); + Uint8 y=GETBYTE(Data+3); + int duration=parser.DecodeValue(GETDWORD(Data+4)); + + // Shake surface + SDL_Surface *source=w_display->GetSurface(0); + SDL_Rect srect={0,0,NativeWidth(),NativeHeight()}; + SDL_Rect erect={x,y,srect.w,srect.h}; + for(int i=0;i36){ + color=parser.DecodeValue(GETDWORD(Data+33)); + } + if(Length>40){ + ccut=parser.DecodeValue(GETDWORD(Data+37)); + } + + if(Length>41){ + LogError("ILLEGAL GP LENGTH:%d",Length); + } + + if(dstx>0xFFFF) dstx|=0xFFFF0000; + if(dsty>0xFFFF) dsty|=0xFFFF0000; + if(srcx>0xFFFF) srcx|=0xFFFF0000; + if(srcy>0xFFFF) srcy|=0xFFFF0000; + if(srcw>0xFFFF) srcw|=0xFFFF0000; + if(srch>0xFFFF) srch|=0xFFFF0000; + + // Convert values + SDL_Rect srcr={srcx,srcy,srcw,srch}; + SDL_Rect dstr={dstx,dsty,srcw,srch}; + + if(src>=0 && srcBlitSurface(src,&srcr,dst,&dstr); + } + else if(cmd==1 || cmd==21){ + w_display->BlendSurface(src,&srcr,dst,&dstr); + } + + + // Effects to copy things to display surface + else if(cmd==15){ + // Some kind of vertical effect -- Destination is duration + w_display->BlitSurface(src,&srcr,0,&dstr); + } + else if(cmd==16){ + // Some kind of horizontal effect -- Destination is duration + w_display->BlitSurface(src,&srcr,0,&dstr); + } + else if(cmd==17){ + // Move effect -- Destination is duration + w_display->BlitSurface(src,&srcr,0,&dstr); + } + else if(cmd==19 || cmd==7){ + // Fade effect -- Destination is duration + w_display->BlendSurface(src,&srcr,0,&dstr); + SDL_Surface *surface=w_display->GetSurface(src); + if(surface){ + AddAnimation(new Fade(dstr,surface,srcr,dst)); + } + } + else{ + LogError("UNKNOWN GP OPCODE:%d",cmd); + for(int i=0;iFillSurface(dst,r,g,b); + } + return false; +} + +// Wait while fading in graphics +bool IkuraDecoder::iop_go(const Uint8 *Data,int Length){ + int delay=parser.DecodeValue(GETDWORD(Data)); + Uint8 r=GETBYTE(Data+4); + Uint8 g=GETBYTE(Data+5); + Uint8 b=GETBYTE(Data+6); + SDL_Surface *tmps=EDL_CreateSurface(NativeWidth(),NativeHeight()); + SDL_Rect src={0,0,tmps->w,tmps->h}; + boxRGBA(tmps,0,0,tmps->w,tmps->h,r,g,b,0xFF); + w_display->SetSurface(0,tmps); + AddAnimation(new Fade(src,tmps,src,delay)); + SDL_FreeSurface(tmps); + + // Set waitstate + if(state==IS_WAITTIMER){ + timerend+=delay; + } + else{ + timerend=SDL_GetTicks()+delay; + state=IS_WAITTIMER; + } + return false; +} + +// Open animation +bool IkuraDecoder::iop_gaopen(const Uint8 *Data,int Length){ + int v=parser.DecodeValue(GETDWORD(Data)); + char *filename=(char*)Data+4; + LogVerbose("Loading animation: %d %s",v,filename); + if(asurfaces){ + for(int i=0;asurfaces[i];i++){ + SDL_FreeSurface(asurfaces[i]); + } + delete asurfaces; + } + asurfaces=LoadAnimation(filename); + return false; +} + +// Start animation +bool IkuraDecoder::iop_gastart(const Uint8 *Data,int Length){ + if(asurfaces){ + PlayAnimation(asurfaces); + asurfaces=0; + } + return !(asurfaces); +} + +// Load video file +bool IkuraDecoder::iop_avip(const Uint8 *Data,int Length){ + int srcw=parser.DecodeValue(GETDWORD(Data+0)); + int srch=parser.DecodeValue(GETDWORD(Data+4)); + int dstw=parser.DecodeValue(GETDWORD(Data+8)); + int dsth=parser.DecodeValue(GETDWORD(Data+12)); + LogVerbose("Play video: %d %d %d %d",srcw,srch,dstw,dsth); + PlayVideo((char*)Data+16); + return true; +} + +// Load graphics +bool IkuraDecoder::iop_gl(const Uint8 *Data,int Length){ + // Load image into the GDL buffers + int index=parser.DecodeValue(GETDWORD(Data)); + uString name=(char*)Data+4; + SDL_Surface *surface=LoadImage(name); + if(surface){ + w_display->SetSurface(index,surface); + SDL_FreeSurface(surface); + } + return false; +} + +// Jump to ssoffset+jumptable[WORD] +bool IkuraDecoder::iop_jp(const Uint8 *Data,int Length){ + parser.JumpFunction(GETWORD(Data)); + return false; +} + +// Jumpswitch +bool IkuraDecoder::iop_onjp(const Uint8 *Data,int Length){ + int reg=parser.DecodeValue(GETDWORD(Data)); + Uint8 cnt=GETBYTE(Data+4); + + // Check if jump is applicable + if(reg>=(int)0 && reg=(int)0 && regDropMap(); + return false; +} + +// Load graphic rect +bool IkuraDecoder::iop_ihgl(const Uint8 *Data,int Length){ + SDL_Surface *hitmap=LoadImage((char*)Data); + if(hitmap){ + w_display->SetMap(hitmap); + SDL_FreeSurface(hitmap); + } + else{ + LogError("Failed to load hitmap:%s",Data); + } + return hitmap; +} + +// Configure keymap for keyboard input +bool IkuraDecoder::iop_ihk(const Uint8 *Data,int Length){ + Uint8 index=GETBYTE(Data); + for(int i=1;iSetKeyMap(index,(i-1)/4,parser.DecodeValue(GETDWORD(Data+i))); + } + return false; +} + +// Set default keymap +bool IkuraDecoder::iop_ihkdef(const Uint8 *Data,int Length){ + w_display->SetKeyDefault(parser.DecodeValue(GETDWORD(Data))); + return false; +} + +// Defines screen areas (Kinda like the widgets) +bool IkuraDecoder::iop_ih(const Uint8 *Data,int Length){ + if(Length==23 || Length==31){ + Uint8 cmd=GETBYTE(Data); + Uint32 x=GETDWORD(Data+1); + Uint32 y=GETDWORD(Data+5); + Uint32 w=GETDWORD(Data+9); + Uint32 h=GETDWORD(Data+13); + //Uint8 type=GETBYTE(Data+17); + //Uint16 flag=GETWORD(Data+18); + //Uint8 c2=GETBYTE(Data+20); + //Uint8 c3=GETBYTE(Data+21); + //Uint8 c4=GETBYTE(Data+22); + + SDL_Rect area={x,y,w-x,h-y}; + w_display->SetSpot(cmd,area); + } + else{ + LogError("FATAL: Unexpected IH opcode format"); + } + return false; +} + +/* + * Example input bflag: + * Snow sakura: 1 (Left button+enter) + * Sagara family: 1 (Left button+enter) + * Sagara family: 0 (Left button+enter simple skip, right cancel) + * Crescendo: 0 (Left button+enter) + * Crescendo: 5 (Left button+enter) + * Crescendo: 4 (Left button+enter) + * + * + * 1: 001 + * 2: 010 + * 4: 100 + * 5: 101 + */ +bool IkuraDecoder::iop_ig(const Uint8 *Data,int Length){ + if(iop_check(6,IOP_IG,Data,Length)){ + // Parse parameters + Uint16 cur=GETWORD(Data); + Uint16 btn=GETWORD(Data+2); + //Uint8 cnt=GETBYTE(Data+4); + //Uint8 bflag=GETBYTE(Data+5); + + // Calculate results + int h=w_display->GetSelected(false); + Sint16 pos=h; + Sint16 flag=0; + if(h!=-1){ + // Check for hotspots input + if(h==w_display->GetResult(false)){ + w_display->GetResult(true); + flag=2; + } + } + else{ + // Get ordinary clicks + if(keycancel){ + keycancel=false; + flag=4; + } + if(keyok){ + keyok=false; + flag=2; + } + } + + // Store results + //LogTest("IG: %d %d %d %d (%d %d)",cur,btn,cnt,bflag,pos,flag); + parser.SetValue(cur,pos); + parser.SetValue(btn,flag); + } + return false; +} + +bool IkuraDecoder::iop_ed(const Uint8 *Data,int Length){ + EventGameDialog(VD_SHUTDOWN); + return true; +} + diff --git a/engines/vileVN/ikura/ikuradecoder.h b/engines/vileVN/ikura/ikuradecoder.h new file mode 100644 index 0000000000..2d46f97b50 --- /dev/null +++ b/engines/vileVN/ikura/ikuradecoder.h @@ -0,0 +1,189 @@ +/*! \class IkuraDecoder + * \brief Engine core and decoder for Ikura GDL based games + */ +#ifndef _IKURADECODER_H_ +#define _IKURADECODER_H_ + +//#include "ikuragui.h" +#include "../engine/evn.h" +#include "iparser.h" +#include "idisplay.h" + +#define IKURA_FONTSTYLE_BOLD 0x01 +#define IKURA_FONTSTYLE_ITALIC 0x02 +#define IKURA_FONTSTYLE_MASK 0x03 +#define IKURA_FONTSTYLE_SHADOW 0x04 + +enum IKURA_FONTSTYLE { + IF_BOLD +}; + + +// Ikura state machine +enum IKURA_STATE { + IS_NORMAL, //!< Normal opcode processing + IS_WAITTIMER, //!< Waiting for statetimer to time out + IS_WAITTEXT, //!< Waiting for text to print + IS_WAITCLICK, //!< Waiting for user input + IS_LOAD, //!< Load dialog + IS_SAVE, //!< Save dialog + IS_OPTIONS //!< Options dialog +}; + +class IkuraDecoder : public EngineVN { + protected: + // Statemachine + IKURA_STATE state; //!< Current state + IParser parser; + + // Timer + Uint32 timerend; //!< End of state timer + Uint32 timerstart; //!< Timer start (milliseconds) + Uint32 delayvalue; //!< Delay duration (milliseconds) + + // Selection data + int selresult; //!< Selection result (-1 = none) + + // Gamedata + Stringlist s_names; //!< Character names (Newer games) + SDL_Surface **asurfaces; //!< Loaded animation + + // ISF Decrypt data + char *isf_keybuffer; + int isf_keysize; + + // Client widgets + IkuraDisplay *w_display; //!< Widget for ingame graphics + Textview *w_textview; //!< Textview control + Selection *w_select; //!< Selection widget + + // Override game events + virtual bool EventGameTick(); + virtual bool EventGameProcess(); + virtual void EventSelect(int Selection); + virtual bool EventSave(int Index); + virtual bool EventLoad(int Index); + virtual void EventGameDialog(VN_DIALOGS Dialog); + virtual bool EventBackgroundMouseRightDown(int X,int Y); + + // Overridden opcode handlers + virtual bool iop_wp(const Uint8 *Data,int Length); + + // Opcode handlers + bool iop_check(int ExpectedLength,const Uint8 Code, + const Uint8 *Data,int Length); + bool iop_unknown(const Uint8 Code,const Uint8 *Data,int Length); + bool iop_calc(const Uint8 *Data,int Length); + bool iop_lsbs(const Uint8 *Data,int Length); + bool iop_sret(const Uint8 *Data,int Length); + bool iop_ls(const Uint8 *Data,int Length); + bool iop_title(const Uint8 *Data,int Length); + bool iop_cns(const Uint8 *Data,int Length); + bool iop_clk(const Uint8 *Data,int Length); + bool iop_setgameinfo(const Uint8 *Data,int Length); + bool iop_ws(const Uint8 *Data,int Length); + bool iop_wss(const Uint8 *Data,int Length); + bool iop_wsh(const Uint8 *Data,int Length); + bool iop_scp(const Uint8 *Data,int Length); + bool iop_ssp(const Uint8 *Data,int Length); + bool iop_if(const Uint8 *Data,int Length); + bool iop_im(const Uint8 *Data,int Length); + bool iop_rt(const Uint8 *Data,int Length); + bool iop_hdec(const Uint8 *Data,int Length); + bool iop_hinc(const Uint8 *Data,int Length); + bool iop_hsg(const Uint8 *Data,int Length); + bool iop_hs(const Uint8 *Data,int Length); + bool iop_ht(const Uint8 *Data,int Length); + bool iop_hxp(const Uint8 *Data,int Length); + bool iop_hp(const Uint8 *Data,int Length); + bool iop_hf(const Uint8 *Data,int Length); + bool iop_sp(const Uint8 *Data,int Length); + bool iop_sk(const Uint8 *Data,int Length); + bool iop_sks(const Uint8 *Data,int Length); + bool iop_hn(const Uint8 *Data,int Length); + bool iop_es(const Uint8 *Data,int Length); + bool iop_ec(const Uint8 *Data,int Length); + bool iop_ft(const Uint8 *Data,int Length); + bool iop_ms(const Uint8 *Data,int Length); + bool iop_ses(const Uint8 *Data,int Length); + bool iop_pcmon(const Uint8 *Data,int Length); + bool iop_pcms(const Uint8 *Data,int Length); + bool iop_pcml(const Uint8 *Data,int Length); + bool iop_cset(const Uint8 *Data,int Length); + bool iop_cw(const Uint8 *Data,int Length); + bool iop_cp(const Uint8 *Data,int Length); + bool iop_cwo(const Uint8 *Data,int Length); + bool iop_cwc(const Uint8 *Data,int Length); + bool iop_wc(const Uint8 *Data,int Length); + bool iop_wo(const Uint8 *Data,int Length); + bool iop_cc(const Uint8 *Data,int Length); + bool iop_ml(const Uint8 *Data,int Length); + bool iop_gge(const Uint8 *Data,int Length); + bool iop_vset(const Uint8 *Data,int Length); + bool iop_gv(const Uint8 *Data,int Length); + bool iop_gp(const Uint8 *Data,int Length); + bool iop_set(const Uint8 *Data,int Length); + bool iop_sep(const Uint8 *Data,int Length); + bool iop_ser(const Uint8 *Data,int Length); + bool iop_gaopen(const Uint8 *Data,int Length); + bool iop_gastart(const Uint8 *Data,int Length); + bool iop_avip(const Uint8 *Data,int Length); + bool iop_gl(const Uint8 *Data,int Length); + bool iop_go(const Uint8 *Data,int Length); + bool iop_gn(const Uint8 *Data,int Length); + bool iop_gc(const Uint8 *Data,int Length); + bool iop_js(const Uint8 *Data,int Length); + bool iop_ppf(const Uint8 *Data,int Length); + bool iop_jp(const Uint8 *Data,int Length); + bool iop_onjp(const Uint8 *Data,int Length); + bool iop_onjs(const Uint8 *Data,int Length); + bool iop_das(const Uint8 *Data,int Length); + bool iop_dap(const Uint8 *Data,int Length); + bool iop_pm(const Uint8 *Data,int Length); + bool iop_pf(const Uint8 *Data,int Length); + bool iop_exc(const Uint8 *Data,int Length); + bool iop_exs(const Uint8 *Data,int Length); + bool iop_sts(const Uint8 *Data,int Length); + bool iop_stx(const Uint8 *Data,int Length); + bool iop_timerset(const Uint8 *Data,int Length); + bool iop_timerget(const Uint8 *Data,int Length); + bool iop_atimes(const Uint8 *Data,int Length); + bool iop_await(const Uint8 *Data,int Length); + bool iop_iginit(const Uint8 *Data,int Length); + bool iop_igrelease(const Uint8 *Data,int Length); + bool iop_ig(const Uint8 *Data,int Length); + bool iop_ih(const Uint8 *Data,int Length); + bool iop_ihgp(const Uint8 *Data,int Length); + bool iop_ihgc(const Uint8 *Data,int Length); + bool iop_ihgl(const Uint8 *Data,int Length); + bool iop_ihk(const Uint8 *Data,int Length); + bool iop_ihkdef(const Uint8 *Data,int Length); + bool iop_opsl(const Uint8 *Data,int Length); + bool iop_svf(const Uint8 *Data,int Length); + bool iop_udae(const Uint8 *Data,int Length); + bool iop_udaf(const Uint8 *Data,int Length); + bool iop_udda(const Uint8 *Data,int Length); + bool iop_voc(const Uint8 *Data,int Length); + bool iop_opprop(const Uint8 *Data,int Length); + bool iop_enable(const Uint8 *Data,int Length); + bool iop_disable(const Uint8 *Data,int Length); + bool iop_sldrset(const Uint8 *Data,int Length); + bool iop_cbset(const Uint8 *Data,int Length); + bool iop_rbset(const Uint8 *Data,int Length); + bool iop_tagset(const Uint8 *Data,int Length); + bool iop_frameset(const Uint8 *Data,int Length); + bool iop_setfontcolor(const Uint8 *Data,int Length); + bool iop_setfontstyle(const Uint8 *Data,int Length); + bool iop_pb(const Uint8 *Data,int Length); + bool iop_gpb(const Uint8 *Data,int Length); + bool iop_ed(const Uint8 *Data,int Length); + public: + IkuraDecoder(int Width,int Height); + ~IkuraDecoder(); + void SetKey(char *Buffer,int Size); + void DecodeScript(Uint8 *Buffer,int Size); + bool RunScript(uString Name); +}; + +#endif + diff --git a/engines/vileVN/ikura/iopcodes.h b/engines/vileVN/ikura/iopcodes.h new file mode 100644 index 0000000000..87ace369b7 --- /dev/null +++ b/engines/vileVN/ikura/iopcodes.h @@ -0,0 +1,199 @@ +/*! \unit iopcodes.h + * \brief defines symbols for ikura op codes + * + * Reversed engineered from the executables. Googletranslated comments. + */ +#ifndef _IKURAOPS_H_ +#define _IKURAOPS_H_ + +#define IOP_EXT 0xFF // Extended treatment +#define IOP_BREAK 0xFE // Break +#define IOP_GRPOUT 0xFD // Image Output +#define IOP_TIMERGET 0xFC // Get Time Counter +#define IOP_TIMEREND 0xFB // Exit Time Counter +#define IOP_TIMERSET 0xFA // Set Time Counter +#define IOP_SETFONTCOLOR 0xF9 // Specifies the font color +#define IOP_SETFONTSTYLE 0xF8 // specify font style +#define IOP_SETGAMEINFO 0xF7 // Setting the in-game information +#define IOP_PPE 0xF6 // ban display settings allow pop-up menu +#define IOP_SVF 0xF5 // save set not to allow +#define IOP_PPF 0xF4 // Display Settings pop-up menu +#define IOP_AVIP 0xF3 // AVI file playback +#define IOP_AWAIT 0xF2 // Wait Wait +#define IOP_ATIMES 0xF1 // Starting weight +#define IOP_CNF 0xF0 // Set the file name bound +#define IOP_EXT2 0xEF // Extended treatment +#define IOP_TITLE 0xE9 // Title Screen +#define IOP_ENABLE 0xE8 // enable Dialog Control +#define IOP_DISABLE 0xE7 // disable the Dialog +#define IOP_OPPROP 0xE6 // Open dialog +#define IOP_OPSL 0xE5 // SAVE/LOAD dialog open +#define IOP_SLDRSET 0xE4 // Settings dialog slider +#define IOP_CBSET 0xE3 // Settings dialog box, check +#define IOP_RBSET 0xE2 // Set the radio button of the dialog +#define IOP_FRAMESET 0xE1 // Settings dialog frame +#define IOP_TAGSET 0xE0 // tagging dialog +#define IOP_MPM2 0xD9 // Multi-view +#define IOP_PM2 0xD8 // character display +#define IOP_VOC 0xD7 // Voice File Name Registration +#define IOP_MPM 0xD6 // execute simultaneous multi-line display +#define IOP_SABL 0xD5 // --- no description --- +#define IOP_PPCRT 0xD4 // return to game to close pop-up menu +#define IOP_PPORT 0xD3 // return pop-up menu +#define IOP_PPTYPE 0xD2 // Setting pop-up menu display type +#define IOP_PPABL 0xD1 // enable disable pop-up menu configuration +#define IOP_PPTL 0xD0 // Set the popup menu title +#define IOP_IROPN 0xBF // --- no description --- +#define IOP_IRCLK 0xBE // --- no description --- +#define IOP_CLKEXMCSET 0xBD // mouse cursor waiting ID extension init +#define IOP_SETSMPRATE 0xB4 // set sample rate +#define IOP_MSGBOX 0xB3 // Display Message Box +#define IOP_CHANGEWALL 0xB2 // wallpaper change +#define IOP_NAMECOPY 0xB1 // Copy Name +#define IOP_INNAME 0xB0 // hero name registration +#define IOP_KIDSCAN 0xA7 // determinate flag read and read features +#define IOP_KIDHABA 0xA6 // characters per line of text read +#define IOP_KIDFN 0xA5 // Set the number of read flags +#define IOP_KIDEND 0xA4 // read and sentences flagged as read +#define IOP_KIDSET 0xA3 // determinate flag read and sentences read +#define IOP_KIDPAGE 0xA2 // Read text pages of information +#define IOP_KIDMOJI 0xA1 // to set the text color of text read +#define IOP_KIDCLR 0xA0 // Initialize read and sentences +#define IOP_SETINSIDEVOL 0x9F // internal volume setting +#define IOP_DAS 0x92 // CDDA Stop +#define IOP_DAP 0x91 // CDDA Playback +#define IOP_DAE 0x90 // CDDA Set +#define IOP_IGN 0x8E // NO Get Cursor +#define IOP_CLK 0x8D // Click wait +#define IOP_IHGP 0x8C // Specify image transfer +#define IOP_IHGC 0x8B // Select Reiautozerokuria +#define IOP_IHGL 0x8A // Image loading layout selection +#define IOP_IHKDEF 0x89 // Keyboard Extension - Set default number +#define IOP_IHK 0x88 // Extended keyboard - the target data set +#define IOP_IGRELEASE 0x87 // mouse input in the screen - free +#define IOP_IGINIT 0x86 // mouse input in the screen - Init +#define IOP_IG 0x85 // mouse input in the screen +#define IOP_IH 0x84 // IG command set selection +#define IOP_IXY 0x83 // Changing the mouse position +#define IOP_IMS 0x82 // mouse movement range setting +#define IOP_IC 0x81 // Changing mouse cursor +#define IOP_IM 0x80 // Reading Mausukasorudeta +#define IOP_PCMCN 0x7F // Backup audio file +#define IOP_PCMGETPOS 0x7E // PCM playback position acquisition +#define IOP_SEGETPOS 0x7D // Get sound effects playback position +#define IOP_BGMGETPOS 0x7C // Get music playback position +#define IOP_SES 0x7B // SES Stop Sound Effects +#define IOP_PCMEND 0x7A // PCM Audio Stop waiting +#define IOP_PCMS 0x79 // PCM Stop +#define IOP_PCML 0x78 // PCM Load +#define IOP_PCMON 0x77 // PCM Audio Playback +#define IOP_SET 0x76 // Disable sound effects +#define IOP_SEP 0x75 // Enable sound effects +#define IOP_SER 0x74 // Loading sound effects +#define IOP_MS 0x73 // Stop the Music +#define IOP_MF 0x72 // Music fades +#define IOP_MP 0x71 // Musical Play +#define IOP_ML 0x70 // playing music, data loading +#define IOP_SGL 0x6F // Load saved image +#define IOP_GADELETE 0x69 // Remove animation +#define IOP_GACLOSE 0x68 // animation file closed +#define IOP_GAPOS 0x67 // Animation Set position +#define IOP_GASET 0x66 // a set of animation data +#define IOP_GAOPEN 0x65 // Opening animation files +#define IOP_GAL 0x64 // Set animation loop +#define IOP_GV 0x63 // Screen shake treatment +#define IOP_GSCRL 0x62 // scroll handle +#define IOP_GPE 0x61 // Scale Processing +#define IOP_GGE 0x60 // effects using grayscale +#define IOP_GPO 0x5F // BGM fade out effects and graphics +#define IOP_GPI 0x5E // BGM fade effects and graphics +#define IOP_GASTOP 0x5D // Stop Animation +#define IOP_GASTART 0x5C // Start animation +#define IOP_PR 0x5B // text display +#define IOP_GPJ 0x5A // Character Set Form +#define IOP_GPB 0x59 // Set Text Size +#define IOP_GB 0x58 // Draw a rectangle +#define IOP_GP 0x57 // Copying graphics +#define IOP_GL 0x56 // Graphic Road Show +#define IOP_GO 0x55 // Gurafikkufedoauto +#define IOP_GI 0x54 // Gurafikkufedoin +#define IOP_GC 0x53 // Clear graphics +#define IOP_GF 0x52 // Graphic display off +#define IOP_GN 0x51 // On graphic display +#define IOP_VSET 0x50 // Virtual Set VRAM +#define IOP_SSP 0x4C // copy parameters to system variables +#define IOP_SCP 0x4B // Copy System Variables +#define IOP_EXC 0x4A // EXA flags secured area +#define IOP_EXS 0x49 // EXA flags set in the command area +#define IOP_EXA 0x48 // extra space to store flags and vars +#define IOP_IF 0x47 // IF-THEN run +#define IOP_HT 0x46 // Transfer variable +#define IOP_HSG 0x45 // assign values to variables together +#define IOP_CALC 0x44 // Calculate +#define IOP_HDEC 0x43 // decrement a variable +#define IOP_HINC 0x42 // Increment a variable +#define IOP_HS 0x41 // assign a value to a variable +#define IOP_HLN 0x40 // set the number of variables +#define IOP_HXP 0x3C // 2 jump determination flag pattern +#define IOP_HN 0x3B // jump flag decision +#define IOP_STX 0x3A // jump judging system flags +#define IOP_EC 0x39 // flag specified load +#define IOP_ES 0x38 // Saves the specified flags +#define IOP_STS 0x37 // Flag for Follow Up System +#define IOP_HP 0x36 // jump determination flag pattern +#define IOP_SP 0x35 // set flag pattern +#define IOP_FT 0x34 // Transfer flag +#define IOP_HF 0x33 // jump flag decision +#define IOP_SKS 0x32 // Set clear reversal flag together +#define IOP_SK 0x31 // reversal clear set of flags +#define IOP_FLN 0x30 // Setting the number of flags +#define IOP_WSS 0x2E // the message window displays +#define IOP_WSH 0x2D // Hidden Message Window +#define IOP_PMP 0x2C // Check character display with audio flag +#define IOP_PM 0x2B // character display +#define IOP_WC 0x2A // Close Window +#define IOP_WO 0x29 // Open Window +#define IOP_PC 0x28 // Character Set Form +#define IOP_PB 0x27 // specify font size +#define IOP_PF 0x26 // Speed Setting Message Display +#define IOP_CNS 0x25 // Set figure name +#define IOP_CN 0x24 // character set name characters +#define IOP_WW 0x23 // Wait Click Settings +#define IOP_WL 0x22 // Wait, click Import Parts +#define IOP_WP 0x21 // Read the window parts +#define IOP_WS 0x20 // Set window position +#define IOP_CTEXT 0x1C // Text Display +#define IOP_CRND 0x1B // Random placement of the command +#define IOP_CRESET 0x1A // Preparing for name of the command set +#define IOP_CCLR 0x19 // Clear the name of the command +#define IOP_CC 0x18 // Run command selection +#define IOP_CWC 0x17 // the Command window closed +#define IOP_CWO 0x16 // Open Command Window +#define IOP_CSET 0x15 // name of the command set +#define IOP_CIP 0x14 // Command Icon +#define IOP_CPS 0x13 // Setting the Character Palette +#define IOP_CIR 0x12 // Loading Icon +#define IOP_CP 0x11 // Read command window frames +#define IOP_CW 0x10 // Location of command window +#define IOP_URL 0x0A // URL address of the call +#define IOP_CHILD 0x09 // child process +#define IOP_ONJS 0x08 // conditional subroutine +#define IOP_ONJP 0x07 // Jump conditions +#define IOP_RT 0x06 // return from subroutine +#define IOP_JS 0x05 // jump subroutine +#define IOP_JP 0x04 // jump +#define IOP_SRET 0x03 // Returning from a sub-scenarios +#define IOP_LSBS 0x02 // load and run sub-scenarios +#define IOP_LS 0x01 // load and run scenarios +#define IOP_ED 0x00 // end + +// Aliased +#define IOP_STC IOP_STX // jump judging system flags + +// Undocumented +#define IOP_UDAE 0xAE +#define IOP_UDAF 0xAF +#define IOP_UDDA 0xDA + +#endif + diff --git a/engines/vileVN/ikura/iparser.cpp b/engines/vileVN/ikura/iparser.cpp new file mode 100644 index 0000000000..5844b6ba43 --- /dev/null +++ b/engines/vileVN/ikura/iparser.cpp @@ -0,0 +1,320 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "iparser.h" + +IParser::IParser() { + // Preset values + scriptstack=0; +} + +IParser::~IParser(){ + while(scriptstack){ + IkuraScript *tmpscript=scriptstack->NextPtr; + delete scriptstack; + scriptstack=tmpscript; + } +} + +/*! \brief Saves parser state and all script positions + * \param File Savegame file to write to + * \return True if the data was successfully stored + */ +bool IParser::Save(Savegame *File){ + // Get save positions + Uint32 count=0; + IkuraScript *tmpptr=scriptstack; + while(tmpptr){ + uString name=tmpptr->Save(File); + File->SaveString(EDL_Format("script-%d",count++),name); + tmpptr=tmpptr->NextPtr; + } + + // Save metadata + File->SaveUint32("stack-size",count); + File->SaveVector("flags",&Flags); + File->SaveVector("vars",&Variables); + return true; +} + +bool IParser::Load(IkuraDecoder *Engine,Savegame *File){ + Uint32 size; + bool retval=false; + if(File->LoadUint32("stack-size",&size)){ + // Flush existing stack + while(scriptstack){ + IkuraScript *script=scriptstack->NextPtr; + delete scriptstack; + scriptstack=script; + } + + // Rebuild old stack + uString name; + IkuraScript *stackptr=0; + for(unsigned int i=0;iLoadString(EDL_Format("script-%d",i),&name)){ + IkuraScript *script=new IkuraScript(); + if(script && script->Load(Engine,File,name)){ + if(stackptr){ + stackptr->NextPtr=script; + stackptr=stackptr->NextPtr; + } + else{ + stackptr=script; + scriptstack=script; + } + } + else if(script){ + delete script; + } + } + } + + // Load metadata + retval=true; + retval&=File->LoadVector("flags",&Flags); + retval&=File->LoadVector("vars",&Variables); + } + return retval; +} + +/*! \brief Returns register value if 32nd bit is set + * \param 31 bit signed value or register address + * \returns 32bit signed value + */ +int IParser::DecodeValue(Uint32 Value){ + // Check 32b signed (Means register value) + if(Value&0x80000000){ + Value=GetValue(Value&~(0x80000000)); + } + if(Value&0x40000000){ + Value|=0x80000000; + } + return Value; +} + +/*! \brief Retrieves a 31 bit signed as a 32bit value + * \param Position Value index + * \returns 32bit signed value + */ +int IParser::GetValue(int Position){ + // Check 32b signed (Means register value) + Uint32 value=Variables.GetUint32(Position); + if(value&0x40000000){ + value|=0x80000000; + } + return value; +} + +/*! \brief Stores a "Uint31" value :) + * \param Position Value index + * \param Value The 31 bit signed value + */ +void IParser::SetValue(int Position,Uint32 Value){ + Variables.SetUint32(Position,Value&~(0x80000000)); +} + +/*! \brief Sets a system flag + * \param Position Which flag to set + * \param Value Value of target flag + * + * Please note that several system flags correspond to "auto" settings + * etc and will be overridden in the decoder stage with dynamic values. + */ +void IParser::SetSystem(int Position,bool Value){ + System.SetBit(Position,Value); +} + +/*! \brief Reads a system flag + * \param Position Which flag to read + * \returns Value of read flag + */ +bool IParser::GetSystem(int Position){ + return System.GetBit(Position); +} + +/*! \brief Sets a flag + * \param Position Which flag to set + * \param Value Value of target flag + */ +void IParser::SetFlag(int Position,bool Value){ + Flags.SetBit(Position,Value); +} + +/*! \brief Reads a flag + * \param Position Which flag to read + * \returns Value of read flag + */ +bool IParser::GetFlag(int Position){ + return Flags.GetBit(Position); +} + +/*! \brief Sets a hitpattern + */ +void IParser::Setpattern(int Index,Uint8 *Buffer,int Size){ + Patterns.SetBuffer(Index,Buffer,Size); +} + +bool IParser::Hitpattern(Uint8 Index,Uint8 Command){ + // Scour trough hitpattern + bool retval=true; + Uint8 *buffer; + int size; + Patterns.GetBuffer(Index,&buffer,&size); + for(int i=0;retval && iGetOpcode(Opcode,Buffer,Length); + } + else{ + return false; + } +} + +/*! \brief Loads a new script while dropping all current data + * \param Script The script resource to load + * \returns True if script was successfully loaded + */ +bool IParser::LoadScript(uString Name,Uint8 *Buffer,int Length,int Pos){ + bool retval=false; + IkuraScript *script=new IkuraScript(); + if(script->Load(Name,Pos,Buffer,Length)){ + while(scriptstack){ + IkuraScript *tmpptr=scriptstack->NextPtr; + delete scriptstack; + scriptstack=tmpptr; + } + scriptstack=script; + retval=true; + } + else{ + delete script; + } + return retval; +} + +/*! \brief Loads a new script while dropping the current one + * \param Script The script resource to load + * \returns True if script was successfully loaded + */ +bool IParser::JumpScript(uString Name,Uint8 *Buffer,int Length){ + bool retval=false; + IkuraScript *script=new IkuraScript(); + if(script->Load(Name,Buffer,Length)){ + if(scriptstack){ + script->NextPtr=scriptstack->NextPtr; + delete scriptstack; + } + scriptstack=script; + retval=true; + } + else{ + delete script; + } + return retval; +} + +/*! \brief Loads a new script while pushing the old one onto the stack + * \param Script The script resource to load + * \returns True if script was successfully loaded + */ + +bool IParser::CallScript(uString Name,Uint8 *Buffer,int Length){ + bool retval=false; + IkuraScript *script=new IkuraScript(); + if(script->Load(Name,Buffer,Length)){ + script->NextPtr=scriptstack; + scriptstack=script; + retval=true; + } + else{ + delete script; + } + + return retval; +} + +/*! \brief Returns from current subscript + * \returns True if a script is running + */ +bool IParser::ReturnScript(){ + if(scriptstack){ + // Remove the head script + IkuraScript *tmpptr=scriptstack->NextPtr; + delete scriptstack; + scriptstack=tmpptr; + } + return scriptstack; +} + +/*! \brief Jumps to an indexed position inside the current script + * \param Table Position index to jump to + * \returns True if jump was within bounds + */ +bool IParser::JumpFunction(Uint16 Table){ + if(scriptstack){ + return scriptstack->Jump(Table); + } + else{ + return false; + } +} + +/*! \brief Calls a subroutine at an indexed position inside the current script + * \param Table Position index to call + * \returns True if call was within bounds + */ +bool IParser::CallFunction(Uint16 Table){ + if(scriptstack){ + return scriptstack->Call(Table); + } + else{ + return false; + } +} + +/*! \brief Returns from a subroutine call + * \returns True if return could be executed + */ +bool IParser::ReturnFunction(){ + if(scriptstack){ + return scriptstack->Return(); + } + else{ + return false; + } +} + + diff --git a/engines/vileVN/ikura/iparser.h b/engines/vileVN/ikura/iparser.h new file mode 100644 index 0000000000..b10cc17a39 --- /dev/null +++ b/engines/vileVN/ikura/iparser.h @@ -0,0 +1,50 @@ +/*! \class IParser + * \brief Parses a Ikura GDL script and handles execution, flags, etc + */ +#ifndef _IPARSER_H_ +#define _IPARSER_H_ + +#include "iscript.h" + +class IParser { + private: + // Script maintainers + IkuraScript *scriptstack; + public: + IParser(); + ~IParser(); + + // Script API + bool LoadScript(uString Name,Uint8 *Buffer,int Length,int Position); + bool JumpScript(uString Name,Uint8 *Buffer,int Length); + bool CallScript(uString Name,Uint8 *Buffer,int Length); + bool ReturnScript(); + bool JumpFunction(Uint16 Table); + bool CallFunction(Uint16 Table); + bool ReturnFunction(); + bool GetOpcode(Uint8 *Opcode,const Uint8 **Buffer,Uint32 *Length); + + // Variable and flags API + int DecodeValue(Uint32 Value); + int GetValue(int Position); + void SetValue(int Position,Uint32 Value); + void SetSystem(int Position,bool Value); + bool GetSystem(int Position); + void SetFlag(int Position,bool Value); + bool GetFlag(int Position); + bool Hitpattern(Uint8 Index,Uint8 Command); + void Setpattern(int Index,Uint8 *Buffer,int Size); + + // Variables and flags + DVector System; //!< System flags + DVector Variables; //!< Variables + DVector Flags; //!< Flags + DBuffer Patterns; //!< Hitpatterns + + // Export savegame data + bool Save(Savegame *File); + bool Load(IkuraDecoder* Engine,Savegame *File); +}; + +#endif + diff --git a/engines/vileVN/ikura/iscript.cpp b/engines/vileVN/ikura/iscript.cpp new file mode 100644 index 0000000000..d0c8f39ba9 --- /dev/null +++ b/engines/vileVN/ikura/iscript.cpp @@ -0,0 +1,396 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "ikuradecoder.h" +#include "iscript.h" + +IkuraScript::IkuraScript(){ + ssoffset=0; + revision=0; + xorkey=0; + reserved=0; + buffer=0; + length=0; + jumptable=0; + positions=0; + NextPtr=0; + save_pos=0; +} + +IkuraScript::~IkuraScript(){ + if(buffer){ + delete [] buffer; + } + if(jumptable){ + delete [] jumptable; + } + while(positions){ + IkuraScriptPosition *tmppos=positions->nextptr; + delete positions; + positions=tmppos; + } +} + +/*! \brief Extracts an opcode from the current script + * \param Opcode One byte buffer for the extracted opcode + * \param Buffer Pointer to the script data for extracted opcode + * \param Length Length of the opcode data + * + * The opcode header has variying size, so the pointer and associated length + * only refers to the data part of the extracted data. The opcode and length + * fields are parsed directly to the relevant parameters + */ +bool IkuraScript::GetOpcode(Uint8 *Opcode,const Uint8 **Buffer,Uint32 *Length){ + bool retval=false; + if(buffer && positions && positions->positionposition; + if(buffer[pos+1]&0x80){ + // Length is two bytes (Between 0x80 and 0x7FFF) + *Opcode=buffer[pos+0]; + *Length=(((buffer[pos+1]&0x7F)<<8)|buffer[pos+2])-3; + *Buffer=buffer+pos+3; + positions->position+=(*Length)+3; + } + else{ + // Length is one byte (Between 0x00 and 0x7F) + *Opcode=buffer[pos+0]; + *Length=buffer[pos+1]-2; + *Buffer=buffer+pos+2; + positions->position+=(*Length)+2; + } + + // Store save information + if(*Opcode==IOP_PM){ + save_name=sname; + save_pos=positions->position; + } + } + return retval; +} + +/*! \brief Jumps to an indexed position inside the current script + * \param Table Position index to jump to + * \returns True if jump was within bounds + */ +bool IkuraScript::Jump(Uint16 Table){ + bool retval=false; + if(positions && jumptable){ + positions->position=ssoffset+jumptable[Table]; + retval=true; + } + return retval; +} + +/*! \brief Calls a subroutine at an indexed position inside the current script + * \param Table Position index to call + * \returns True if call was within bounds + */ +bool IkuraScript::Call(Uint16 Table){ + bool retval=false; + if(positions){ + // Copy old position as a safety precausion and stack it + IkuraScriptPosition *newpos=new IkuraScriptPosition; + newpos->position=positions->position; + newpos->nextptr=positions; + positions=newpos; + retval=Jump(Table); + } + return retval; +} + +/*! \brief Returns from an earlier subroutine call + * \return True if a position was pushed + */ +bool IkuraScript::Return(){ + bool retval=false; + if(positions){ + IkuraScriptPosition *newpos=positions->nextptr; + delete positions; + positions=newpos; + retval=true; + } + return retval; +} + +/*! \brief Saves script positions + * \param File Savegame file + * \return Name of saved script + */ +uString IkuraScript::Save(Savegame *File){ + // Store script positions + int count=0; + IkuraScriptPosition *tmpptr=positions; + while(tmpptr){ + uString n=EDL_Format("%s-%d",save_name.c_str(),count++); + int p=tmpptr->position; + File->SaveUint32(n,p); + tmpptr=tmpptr->nextptr; + } + File->SaveUint32(EDL_Format("%s-save",save_name.c_str()),save_pos); + File->SaveUint32(EDL_Format("%s-size",save_name.c_str()),count); + return save_name; +} + +/*! \brief Reloads old state from savegame + * \param Engine Engine object to load scripts from + * \param File Savegame file to read old states from + * \param Script Name of the script to load + */ +bool IkuraScript::Load(IkuraDecoder *Engine,Savegame *File,uString Script){ + RWops *blob=0; + if((blob=Engine->LoadScript(Script))){ + int tlength=blob->Seek(0,SEEK_END); + if(tlength>(int)0){ + blob->Seek(0,SEEK_SET); + Uint8 *tbuffer=new Uint8[tlength]; + if(blob->Read(tbuffer,tlength)>(int)0){ + // Load script + Engine->DecodeScript(tbuffer,tlength); + Load(Script,tbuffer,tlength); + + // Flush existing stack + while(positions){ + IkuraScriptPosition *tmpptr=positions->nextptr; + delete positions; + positions=tmpptr; + } + + // Recreate position stack + Uint32 p=0; + Uint32 count=0; + IkuraScriptPosition *stackptr=0; + File->LoadUint32(EDL_Format("%s-size",Script.c_str()),&count); + for(unsigned int i=0;iLoadUint32(n,&p)){ + if(stackptr){ + stackptr->nextptr=new IkuraScriptPosition; + stackptr=stackptr->nextptr; + } + else{ + stackptr=new IkuraScriptPosition; + positions=stackptr; + } + stackptr->position=p; + stackptr->nextptr=0; + } + } + + // Reset safe position + if(File->LoadUint32(EDL_Format("%s-save",Script.c_str()),&p)){ + save_pos=p; + if(positions){ + positions->position=p; + } + } + } + delete [] tbuffer; + } + delete blob; + } + return true; +} + +/*! \brief Loads an Ikura/DRS script and sets a starting position + * \param Filename Resource name + * \param Uint32 Pos Starting position + * \returns True if script was valid + * + * This variation is used to load savegames! + */ +bool IkuraScript::Load(uString Name,Uint32 Pos,Uint8 *Buffer,Uint32 Length){ + bool retval=Load(Name,Buffer,Length); + if(retval && Pos>0){ + positions->position=Pos; + } + return retval; +} + +/*! \brief Loads an Ikura/DRS script and sets a starting position + * \param Filename Resource name + * \returns True if script was valid + */ +bool IkuraScript::Load(uString Name,Uint8 *Buffer,Uint32 Length){ + bool retval=false; + if(!strncmp((char*)Buffer,"DigitalRomanceSystem.",21)){ + retval=LoadDRS(Name,Buffer,Length); + } + else{ + retval=LoadISF(Name,Buffer,Length); + } + return retval; +} + +/*! \brief Loads an Ikura script + * \param Filename Resource name + * \returns True if script was valid + */ +bool IkuraScript::LoadISF(uString Name,Uint8 *Buffer,Uint32 Length){ + // Verify jumptable before conversion + bool retval=false; + ssoffset=Buffer[0]|(Buffer[1]<<8)|(Buffer[2]<<16)|(Buffer[3]<<24); + int tablecount=(ssoffset-8)/4; + double tabletest=(ssoffset-8)/(double)4; + if(tablecount==tabletest){ + // Decrypt buffer + if(buffer){ + delete [] buffer; + } + length=Length; + buffer=new Uint8[length]; + for(unsigned int i=0;i<8;i++){ + buffer[i]=Buffer[i]; + } + for(unsigned int i=8;i>2))&0xFF); + } + + /* + uString dumpname=Name+".isf.dump"; + FILE *f=fopen(dumpname.c_str(),"wb"); + if(f){ + fwrite(buffer,1,length,f); + fclose(f); + exit(99999); + } + */ + + // Create jumptable (Might be zero so pad it) + if(jumptable){ + delete [] jumptable; + } + jumptable=new Uint32[tablecount+1]; + for(int i=0;inextptr; + delete positions; + positions=tmppos; + } + positions=new IkuraScriptPosition; + positions->position=ssoffset; + positions->nextptr=0; + + // Complete object data + revision=buffer[5]|(buffer[4]<<8); + xorkey=buffer[6]; + reserved=buffer[7]; + sname=Name; + retval=true; + + // Verify metadata + LogDebug("revision: 0x%04x",revision); + LogDebug("xorkey: 0x%02x",xorkey); + LogDebug("reserved: 0x%02x",reserved); + } + else{ + LogError("Illegal jumptable in script file %s (%d/%d)", + Name.c_str(),tablecount,tabletest); + } + return retval; +} + +/*! \brief Loads a Digital Romance System script + * \param Filename Resource name + * \returns True if script was valid + */ +bool IkuraScript::LoadDRS(uString Name,Uint8 *Buffer,Uint32 Length){ + // Decrypt buffer + bool retval=false; + int pos=0x19; + if(buffer){ + delete [] buffer; + } + length=Length; + buffer=new Uint8[length]; + for(int i=0;i>2))&0xFF); + } + + /* + uString dumpname=Name+".drs.dump"; + FILE *f=fopen(dumpname.c_str(),"wb"); + if(f){ + fwrite(buffer,1,length,f); + fclose(f); + exit(99999); + } + */ + + // Create jump table (Might be zero so pad it) + int tsize=buffer[pos+0]|(buffer[pos+1]<<8)| + (buffer[pos+2]<<16)|(buffer[pos+3]<<24); + int num=buffer[pos+4]|(buffer[pos+5]<<8)| + (buffer[pos+6]<<16)|(buffer[pos+7]<<24); + int tablecount=(tsize)/4; + double tabletest=(tsize)/(double)4; + pos+=8; + if(jumptable){ + delete [] jumptable; + } + jumptable=new Uint32[tablecount+1]; + for(int i=0;inextptr; + delete positions; + positions=tmppos; + } + positions=new IkuraScriptPosition; + positions->position=ssoffset; + positions->nextptr=0; + sname=Name; + retval=true; + return retval; +} + + diff --git a/engines/vileVN/ikura/iscript.h b/engines/vileVN/ikura/iscript.h new file mode 100644 index 0000000000..28bef1a4ba --- /dev/null +++ b/engines/vileVN/ikura/iscript.h @@ -0,0 +1,66 @@ +/*! \class IkuraCore + * \brief Encapsulates data for Ikura Script Files (ISF) + */ +#ifndef _ISCRIPT_H_ +#define _ISCRIPT_H_ + +// Include base system +#include "iopcodes.h" +#include "../common/log.h" +#include "../common/dvector.h" +#include "../common/dbuffer.h" +#include "../common/savegame.h" +#include "../res/rwops.h" + +#define GETBYTE(B) ((B)[0]) +#define GETWORD(B) ((B)[0]|((B)[1]<<8)) +#define GETDWORD(B) ((B)[0]|((B)[1]<<8)|((B)[2]<<16)|((B)[3]<<24)) + +// Forward declare engine interface +class IkuraDecoder; + +// Script maintainers +struct IkuraScriptPosition { //!< Struct for stacking positions + Uint32 position; //!< Stored jump position + IkuraScriptPosition *nextptr; //!< Next stacked position +}; + +// Declare main script interface +class IkuraScript { + private: + Uint32 ssoffset; //!< Offset to script section + Uint16 revision; //!< Script revision code + Uint8 xorkey; //!< Key for xor + Uint8 reserved; //!< Unused + Uint8 *buffer; //!< Script data + unsigned int length; //!< Size of script buffer + Uint32 *jumptable; //!< Table of script positions + Uint32 *calltable; //!< Table of script positions + uString sname; //!< Name of script resource + IkuraScriptPosition *positions; //!< Stacks positions + uString save_name; //!< Remembers script name + Uint32 save_pos; //!< Stores safe save position + public: + IkuraScript(); + ~IkuraScript(); + + // Script API + bool GetOpcode(Uint8 *Opcode,const Uint8 **Buffer,Uint32 *Length); + bool Load(uString Name,Uint32 Pos,Uint8 *Buffer,Uint32 Length); + bool Load(uString Name,Uint8 *Buffer,Uint32 Length); + bool LoadISF(uString Name,Uint8 *Buffer,Uint32 Length); + bool LoadDRS(uString Name,Uint8 *Buffer,Uint32 Length); + bool Jump(Uint16 Table); + bool Call(Uint16 Table); + bool Return(); + + // Savegame interface + bool Load(IkuraDecoder *Engine,Savegame *File,uString Script); + uString Save(Savegame *File); + + // Stacker + IkuraScript *NextPtr; +}; + +#endif + diff --git a/engines/vileVN/ikura/kana/kana.cpp b/engines/vileVN/ikura/kana/kana.cpp new file mode 100644 index 0000000000..62c4412842 --- /dev/null +++ b/engines/vileVN/ikura/kana/kana.cpp @@ -0,0 +1,42 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "kana.h" + +Kana::Kana(uString Path) : DRSDecoder(640,480){ + // Load resources + AddScripts(new ArchiveIkura(Path+"DRSSNR")); + AddImages(new ArchiveIkura(Path+"DRSGRP")); + AddSE(new ArchiveIkura(Path+"DRSSEF")); + AddVideo(new ArchiveFiles(Path+"OP.DOM")); + + // Configure textview + w_textview->Move(0,0); + w_textview->Resize(640,480); + w_textview->SetTextPosition(20,20,600,460); + w_textview->SetAlpha(128); + + // Load standard boot script + RunScript("START.ISF"); +} + +const uString Kana::NativeID(){ + return "Kana"; +} + +const uString Kana::NativeName(){ + return "Kana ~ Little Sister"; +} + diff --git a/engines/vileVN/ikura/kana/kana.h b/engines/vileVN/ikura/kana/kana.h new file mode 100644 index 0000000000..ed06f5819f --- /dev/null +++ b/engines/vileVN/ikura/kana/kana.h @@ -0,0 +1,19 @@ +/*! \class Kana + * \brief Loader class for the drs classic + */ +#ifndef _KANA_H_ +#define _KANA_H_ + +#include "../drsdecoder.h" + +class Kana : public DRSDecoder { + private: + // Override game attributes + const uString NativeID(); + const uString NativeName(); + public: + Kana(uString Path); +}; + +#endif + diff --git a/engines/vileVN/ikura/kanaoka/kanaoka.cpp b/engines/vileVN/ikura/kanaoka/kanaoka.cpp new file mode 100644 index 0000000000..642ec94074 --- /dev/null +++ b/engines/vileVN/ikura/kanaoka/kanaoka.cpp @@ -0,0 +1,53 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "kanaoka.h" + +KanaOkaeri::KanaOkaeri(uString Path) : IkuraDecoder(640,480){ + // Load resources + AddScripts(new ArchiveIkura(Path+"ISF")); + AddImages(new ArchiveIkura(Path+"GGD")); + AddVoices(new ArchiveIkura(Path+"VOICE")); + AddSE(new ArchiveIkura(Path+"SE")); + AddBGM(new ArchiveIkura(Path+"WMSC")); + AddBGM(new ArchiveIkura(Path+"MIDI")); + AddVideo(new ArchiveIkura(Path+"DOLOGO.MPG")); + + // Configure textview + w_textview->Move(0,0); + w_textview->Resize(640,480); + w_textview->SetTextPosition(20,20,600,460); + w_textview->SetAlpha(128); + + /* + char *ttt=new char[36865]; + for(int i=0;i<36865;i++){ + ttt[i]=kanakey[i]; + printf("%c",kanakey[i]); + } + */ + + // Load standard boot script + RunScript("START.ISF"); +} + +const uString KanaOkaeri::NativeID(){ + return "KanaOkaeri"; +} + +const uString KanaOkaeri::NativeName(){ + return "Kana ... Okaeri!"; +} + diff --git a/engines/vileVN/ikura/kanaoka/kanaoka.h b/engines/vileVN/ikura/kanaoka/kanaoka.h new file mode 100644 index 0000000000..13ce20bc91 --- /dev/null +++ b/engines/vileVN/ikura/kanaoka/kanaoka.h @@ -0,0 +1,19 @@ +/*! \class KanaOkaeri + * \brief Loader class for the Ikuragame + */ +#ifndef _KANAOKA_H_ +#define _KANAOKA_H_ + +#include "../ikuradecoder.h" + +class KanaOkaeri : public IkuraDecoder { + private: + // Override game attributes + const uString NativeID(); + const uString NativeName(); + public: + KanaOkaeri(uString Path); +}; + +#endif + diff --git a/engines/vileVN/ikura/sagara/sagara.cpp b/engines/vileVN/ikura/sagara/sagara.cpp new file mode 100644 index 0000000000..82a00915b7 --- /dev/null +++ b/engines/vileVN/ikura/sagara/sagara.cpp @@ -0,0 +1,489 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "sagara.h" + +Sagara::Sagara(uString Path) : IkuraDecoder(640,480){ + // Load resources + AddScripts(new ArchiveIkura(Path+"ISF")); + AddImages(new ArchiveIkura(Path+"GGD")); + AddVoices(new ArchiveIkura(Path+"VOICE")); + AddSE(new ArchiveIkura(Path+"SE")); + AddBGM(new ArchiveIkura(Path+"WMSC")); + AddBGM(new ArchiveIkura(Path+"MIDI")); + CreateTextview(); + + // Load standard boot script + RunScript("START.ISF"); +} + +const uString Sagara::NativeID(){ + return "Sagara"; +} + +const uString Sagara::NativeName(){ + return "The Sagara Family"; +} + +void Sagara::CreateTextview(){ + // Load textwindow graphic and prepare widget + w_textview->SetTextPosition(20,70,600,70); + SDL_Surface *tmpsurface=LoadImage("m_win.gg3"); + SDL_Surface *tmpbuttons=LoadImage("m_win_p.gg3"); + if(tmpsurface && tmpbuttons){ + // Set window graphics + w_textview->Resize(tmpsurface->w,tmpsurface->h); + w_textview->Set(tmpsurface); + SDL_FreeSurface(tmpsurface); + + // Get size of individual button + int bw=tmpbuttons->w/7; + int bh=tmpbuttons->h/4; + + // Save button + BitmapButton *w_save=new BitmapButton(); + w_save->Move(496,6); + w_save->Resize(bw,bh); + w_save->SetState(WS_NORMAL,tmpbuttons,0,bh*0,bw,bh); + w_save->SetState(WS_HOVER,tmpbuttons,0,bh*1,bw,bh); + w_save->SetState(WS_SELECT,tmpbuttons,0,bh*2,bw,bh); + w_save->SetState(WS_DISABLE,tmpbuttons,0,bh*3,bw,bh); + w_textview->SetSaveButton(w_save); + + // Load button + BitmapButton *w_load=new BitmapButton(); + w_load->Move(496,6+bh); + w_load->Resize(bw,bh); + w_load->SetState(WS_NORMAL,tmpbuttons,bw,bh*0,bw,bh); + w_load->SetState(WS_HOVER,tmpbuttons,bw,bh*1,bw,bh); + w_load->SetState(WS_SELECT,tmpbuttons,bw,bh*2,bw,bh); + w_load->SetState(WS_DISABLE,tmpbuttons,bw,bh*3,bw,bh); + w_textview->SetLoadButton(w_load); + + // Skip checkbox + ValueButton *w_skip=new ValueButton(); + SDL_Rect skipclear={bw*2,0,bw,bh}; + SDL_Rect skipset={bw*3,0,bw,bh}; + w_skip->Move(496+bw,6); + w_skip->Resize(bw,bh); + w_skip->SetState(WS_NORMAL,tmpbuttons,&skipclear,tmpbuttons,&skipset); + skipset.y+=bh; + skipclear.y+=bh; + w_skip->SetState(WS_HOVER,tmpbuttons,&skipclear,tmpbuttons,&skipset); + skipset.y+=bh; + skipclear.y+=bh; + w_skip->SetState(WS_SELECT,tmpbuttons,&skipclear,tmpbuttons,&skipset); + skipset.y+=bh; + skipclear.y+=bh; + w_skip->SetState(WS_DISABLE,tmpbuttons,&skipclear,tmpbuttons,&skipset); + w_textview->SetSkipButton(w_skip); + + // Autobutton + BitmapButton *w_auto=new BitmapButton(); + w_auto->Move(496+bw,6+bh); + w_auto->Resize(bw,bh); + w_auto->SetState(WS_NORMAL,tmpbuttons,bw*4,bh*0,bw,bh); + w_auto->SetState(WS_HOVER,tmpbuttons,bw*4,bh*1,bw,bh); + w_auto->SetState(WS_SELECT,tmpbuttons,bw*4,bh*2,bw,bh); + w_auto->SetState(WS_DISABLE,tmpbuttons,bw*4,bh*3,bw,bh); + w_textview->SetAutoButton(w_auto); + + // Optionbutton + BitmapButton *w_option=new BitmapButton(); + w_option->Move(496+bw*2,6); + w_option->Resize(bw,bh); + w_option->SetState(WS_NORMAL,tmpbuttons,bw*5,bh*0,bw,bh); + w_option->SetState(WS_HOVER,tmpbuttons,bw*5,bh*1,bw,bh); + w_option->SetState(WS_SELECT,tmpbuttons,bw*5,bh*2,bw,bh); + w_option->SetState(WS_DISABLE,tmpbuttons,bw*5,bh*3,bw,bh); + w_textview->SetOptionButton(w_option); + + // Backlog button + BitmapButton *w_backlog=new BitmapButton(); + w_backlog->Move(496+bw*2,6+bh); + w_backlog->Resize(bw,bh); + w_backlog->SetState(WS_NORMAL,tmpbuttons,bw*6,bh*0,bw,bh); + w_backlog->SetState(WS_HOVER,tmpbuttons,bw*6,bh*1,bw,bh); + w_backlog->SetState(WS_SELECT,tmpbuttons,bw*6,bh*2,bw,bh); + w_backlog->SetState(WS_DISABLE,tmpbuttons,bw*6,bh*3,bw,bh); + w_textview->SetBackButton(w_backlog); + + SDL_FreeSurface(tmpbuttons); + } + else{ + LogError("Failed to load textview graphics"); + } +} + +/* +void Sagara::EventShowSave(){ + // Set background + SDL_Surface *bgsurface=LoadImage("save_b.gg3"); + SDL_Surface *fgsurface=LoadImage("sl_p.gg3"); + if(bgsurface && fgsurface){ + // Set background + SetDialogGraphics(IW_BACKGROUND,bgsurface); + + // Create loadbutton + SDL_Rect normal={0,0,32,24}; + SDL_Rect hover={0,normal.h*1,normal.w,normal.h}; + SDL_Rect select={0,normal.h*2,normal.w,normal.h}; + SDL_Rect dst={448,8,normal.w,normal.h}; + for(int i=IW_SAVELOAD_PAGE_0;i<=IW_SAVELOAD_PAGE_4;i++){ + SetDialogButton((IKURA_WIDGET)i,fgsurface, + dst,normal,hover,select,normal); + dst.x+=normal.w; + normal.x+=normal.w; + hover.x+=normal.w; + select.x+=normal.w; + } + + // Create exitbutton + normal.w=100; + hover.w=normal.w; + select.w=normal.w; + dst.x=510; + dst.y=448; + dst.w=normal.w; + SetDialogButton(IW_SAVELOAD_EXIT,fgsurface, + dst,normal,hover,select,normal); + + // Create slabs + SDL_Rect bgslab={32,41,280,80}; + SDL_Rect fgslab={0,184,280,80}; + SDL_Rect si={10,10,86,60}; + SDL_Rect st={110,10,160,60}; + dst.x=bgslab.x; + dst.y=bgslab.y; + dst.w=bgslab.w; + dst.h=bgslab.h; + uString savename; + for(int i=IW_SAVELOAD_SLAB_0;iw,tmpsurface->h); + SetTextviewBackground(tmpsurface); + SDL_FreeSurface(tmpsurface); + } + + // Load and assign overlay graphics for skip + SDL_Surface *tmpbuttons=LoadImage("m_skip.gg3"); + if(tmpbuttons){ + int bw=tmpbuttons->w/4; + int bh=tmpbuttons->h; + SDL_Rect rdst={376,368,bw,bh}; + SDL_Rect rnormal={bw*1,0,bw,bh}; + SDL_Rect rhover={bw*2,0,bw,bh}; + SDL_Rect rselect={bw*3,0,bw,bh}; + SDL_Rect rdisable={bw*0,0,bw,bh}; + SetTextviewValue(IW_TEXTVIEW_SKIP,tmpbuttons,rdst, + rnormal,rhover,rselect,rdisable, + rselect,rselect,rselect,rdisable); + SDL_FreeSurface(tmpbuttons); + } + + // Load and assign overlay graphics for automode + tmpbuttons=LoadImage("m_auto.gg3"); + if(tmpbuttons){ + int bw=tmpbuttons->w/4; + int bh=tmpbuttons->h; + SDL_Rect rdst={448,368,bw,bh}; + SDL_Rect rnormal={bw*1,0,bw,bh}; + SDL_Rect rhover={bw*2,0,bw,bh}; + SDL_Rect rselect={bw*3,0,bw,bh}; + SDL_Rect rdisable={bw*0,0,bw,bh}; + SetTextviewButton(IW_TEXTVIEW_AUTO,tmpbuttons,rdst, + rnormal,rhover,rselect,rdisable); + SDL_FreeSurface(tmpbuttons); + } + + // Load and assign overlay graphics for menu + tmpbuttons=LoadImage("m_menu.gg3"); + if(tmpbuttons){ + int bw=tmpbuttons->w; + int bh=tmpbuttons->h/4; + SDL_Rect rdst={520,368,bw,bh}; + SDL_Rect rnormal={0,bh*1,bw,bh}; + SDL_Rect rhover={0,bh*2,bw,bh}; + SDL_Rect rselect={0,bh*3,bw,bh}; + SDL_Rect rdisable={0,bh*0,bw,bh}; + SetTextviewButton(IW_TEXTVIEW_MENU,tmpbuttons,rdst, + rnormal,rhover,rselect,rdisable); + SDL_FreeSurface(tmpbuttons); + } + */ +} + diff --git a/engines/vileVN/ikura/snow/snow.h b/engines/vileVN/ikura/snow/snow.h new file mode 100644 index 0000000000..a4e06625af --- /dev/null +++ b/engines/vileVN/ikura/snow/snow.h @@ -0,0 +1,17 @@ +/*! \class Snow + * \brief Loader class for Snow Family + */ +#ifndef _SNOW_H_ +#define _SNOW_H_ + +#include "../ikuradecoder.h" + +class Snow : public IkuraDecoder { + private: + void CreateTextview(); + public: + Snow(uString Path); +}; + +#endif + diff --git a/engines/vileVN/jast/jast.cpp b/engines/vileVN/jast/jast.cpp new file mode 100644 index 0000000000..83ab41940b --- /dev/null +++ b/engines/vileVN/jast/jast.cpp @@ -0,0 +1,1408 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "jast.h" + + +EngineJAST::EngineJAST(int Width,int Height) : EngineVN(Width,Height){ + // Set defaults + scriptbuffer=0; + scriptlength=0; + scriptindex=0; + choices=0; + labels=0; + filenames=0; + s_background=0; + state=JASTSTATE_NORMAL; + choicemain=choicesub=0; + EDL_SETRECT(r_display,80,16,480,296); + + // Set fixed black background + Widget *bg=new Widget(); + bg->Resize(640,480); + bg->Fill(0,0,0,0xFF); + AddWidget(bg,VL_BACKGROUND); + + // Prepp widgets + w_display=new Widget(); + w_display->Move(0,40); + w_display->Resize(640,400); + AddWidget(w_display,VL_BACKGROUND); + w_tv=new Textview(this); + w_tv->SetTextPosition(0,0,500,62); + w_tv->MoveDialog(70,368); + w_tv->Resize(500,66); + AddWidget(w_tv,VL_TEXTVIEW); + w_sel=0; +} + +EngineJAST::~EngineJAST(){ + ClearFilenames(); + ClearChoice(); + ClearLabel(); + if(s_background){ + SDL_FreeSurface(s_background); + } +} + +/*! \brief Counts parameters in a line (Including command) + * \param Line Script line to scan + * \return Number of parameters including command + */ +int EngineJAST::GetParamCount(uString Line){ + int retval=0; + if(Line.length()){ + retval++; + for(unsigned int i=0;icaption!=label){ + tmpptr=tmpptr->next; + } + if(tmpptr){ + scriptlabel=Label; + scriptindex=tmpptr->index; + } + return tmpptr; +} + +/*! \brief Extracts and trims the current script line (if any!) + * \return Line of code (Blank if failed) + */ +uString EngineJAST::GetCurrentLine(){ + uString retval; + if(scriptbuffer && scriptindex && scriptlength){ + // Skip to the real meat + while(scriptindexname=EDL_Trim(EDL_Upper(Name),true,true); + newptr->type=EDL_Trim(EDL_Upper(Type),true,true); + newptr->next=0; + if(filenames){ + FILENAME_TYPE *tmp=filenames; + while(tmp->next){ + tmp=tmp->next; + } + tmp->next=newptr; + } + else{ + filenames=newptr; + } +} + +/*! \brief Flushes any buffered labels and positions + * + * This method should be called whenever you are loading a new script + */ +void EngineJAST::ClearFilenames(){ + while(filenames){ + FILENAME_TYPE *tmp=filenames->next; + delete filenames; + filenames=tmp; + } +} + +/*! \brief Registers a position and associates it with a textual label + * \param Caption Textual label (Typicall M1, M2, etc) + * \param Index Position in the script for this label + */ +void EngineJAST::AddLabel(uString Caption,int Index){ + LABEL_TYPE *newptr=new LABEL_TYPE; + newptr->caption=EDL_Lower(Caption); + newptr->index=Index; + newptr->next=0; + if(labels){ + LABEL_TYPE *tmp=labels; + while(tmp->next){ + tmp=tmp->next; + } + tmp->next=newptr; + } + else{ + labels=newptr; + } +} + +/*! \brief Flushes any buffered labels and positions + * + * This method should be called whenever you are loading a new script + */ +void EngineJAST::ClearLabel(){ + while(labels){ + LABEL_TYPE *tmp=labels->next; + delete labels; + labels=tmp; + } +} + +/*! \brief Adds a main menu item + * \param ID Choice label in script (Typically VV1, VV2, etc) + */ +void EngineJAST::AddChoice(uString ID){ + CHOICE_TYPE *checkptr=choices; + while(checkptr && checkptr->id!=ID){ + checkptr=checkptr->next; + } + if(!checkptr && GetLine(ID)){ + uString vv=GetCurrentLine(); + CHOICE_TYPE *newptr=new CHOICE_TYPE; + newptr->index=GetParam(vv,1).to_int(); + newptr->caption=EDL_Trim(EDL_Upper(GetParam(vv,2)),true,false); + newptr->id=ID; + newptr->visible=true; + newptr->sub=0; + newptr->next=0; + if(choices){ + CHOICE_TYPE *tmp=choices; + while(tmp->next){ + tmp=tmp->next; + } + tmp->next=newptr; + } + else{ + choices=newptr; + } + } +} + +/*! \brief Adds a submenu item + * \param ID Choice label in script (Typically VV1, VV2, etc) + * \param SubID Choice sub label in script (Typically NN1, NN2, etc) + */ +void EngineJAST::AddChoice(uString ID,uString SubID){ + // Get main menu object + CHOICE_TYPE *vvptr=choices; + while(vvptr && vvptr->id!=ID){ + vvptr=vvptr->next; + } + + // Attach a sub menu + if(vvptr){ + CHOICE_TYPE *checkptr=vvptr->sub; + while(checkptr && checkptr->id!=ID){ + checkptr=checkptr->next; + } + if(!checkptr && GetLine(SubID)){ + uString nn=GetCurrentLine(); + CHOICE_TYPE *newptr=new CHOICE_TYPE; + newptr->index=GetParam(nn,1).to_int(); + newptr->caption=EDL_Trim(EDL_Upper(GetParam(nn,2)),true,false); + newptr->id=SubID; + newptr->visible=true; + newptr->sub=0; + newptr->next=0; + if(vvptr->sub){ + CHOICE_TYPE *tmp=vvptr->sub; + while(tmp->next){ + tmp=tmp->next; + } + tmp->next=newptr; + } + else{ + vvptr->sub=newptr; + } + } + else{ + LogError("Invalid SubID:%s",SubID.c_str()); + } + } + else{ + LogError("Could not find ID:%s",ID.c_str()); + } +} + +void EngineJAST::ClearChoice(){ + CHOICE_TYPE *tmp; + while(choices){ + while(choices->sub){ + tmp=choices->sub->next; + delete choices->sub; + choices->sub=tmp; + } + tmp=choices->next; + delete choices; + choices=tmp; + } +} + +bool EngineJAST::LoadJASTScript(uString Script){ + bool retval=false; + RWops *blob=0; + uString sname=EDL_Searchname(Script); + if((blob=LoadScript(Script))){ + // Extract and verify data + LogVerbose("Loading JAST script: %s",Script.c_str()); + int tlength=blob->Seek(0,SEEK_END); + if(tlength>(int)0){ + // Replace blob + blob->Seek(0,SEEK_SET); + Uint8 *tbuffer=new Uint8[tlength]; + if(blob->Read(tbuffer,tlength)>(int)0){ + // Apply game patches + if(Script=="SK_102.OVL"){ + LogVerbose("Applying patch:%c",tbuffer[1120]); + tbuffer[1120]='6'; + } + + // Store buffer + if(scriptbuffer){ + delete [] scriptbuffer; + } + scriptbuffer=tbuffer; + scriptlength=tlength; + scriptindex=0; + + // Unset variables + for(int i=0;i<256;i++){ + vars.SetUint8(i,0); + } + + // Rig down old stuff + if(w_sel){ + DestroyWidget(w_sel); + w_sel=0; + } + w_tv->ClearText(); + ClearChoice(); + ClearLabel(); + ClearFilenames(); + + // Parse labels + int linestart=0; + for(int i=0;ilinestart && i-20id!=vvid){ + lastchoice=topchoice; + topchoice=topchoice->next; + } + if(topchoice && lastchoice){ + lastchoice->next=topchoice->next; + } + if(topchoice && !lastchoice){ + choices=choices->next; + } + + + // Add to new stack + if(newtopchoices){ + CHOICE_TYPE *tmpchoice=newtopchoices; + while(tmpchoice && tmpchoice->next){ + tmpchoice=tmpchoice->next; + } + tmpchoice->next=topchoice; + topchoice->next=0; + } + else{ + newtopchoices=topchoice; + topchoice->next=0; + } + + // Rearrange sublevel choice in the same manner + if(topchoice){ + CHOICE_TYPE *newsubchoices=0; + CHOICE_TYPE *subchoice=0; + for(int index=2;true;index++){ + uString nnid=GetParam(sx,index); + if(nnid=="-1" || nnid==""){ + break; + } + lastchoice=0; + subchoice=topchoice->sub; + while(subchoice && subchoice->id!=nnid){ + lastchoice=subchoice; + subchoice=subchoice->next; + } + if(subchoice && lastchoice){ + lastchoice->next=subchoice->next; + } + if(subchoice && !lastchoice){ + topchoice->sub=topchoice->sub->next; + } + if(newsubchoices){ + CHOICE_TYPE *tmpchoice=newsubchoices; + while(tmpchoice->next){ + tmpchoice=tmpchoice->next; + } + tmpchoice->next=subchoice; + subchoice->next=0; + } + else{ + newsubchoices=subchoice; + subchoice->next=0; + } + } + + // Drop any remaining subchoices + while(topchoice->sub){ + LogError("Cannot arrange choice: %s", + topchoice->sub->caption.c_str()); + CHOICE_TYPE *tmpchoice=topchoice->sub->next; + delete topchoice->sub; + topchoice->sub=tmpchoice; + } + topchoice->sub=newsubchoices; + } + else{ + LogError("Could not find topchoice: %s", + vvid.c_str()); + } + } + } + while(choices){ + LogError("Cannot arrange choice: %s", + choices->caption.c_str()); + CHOICE_TYPE *tmpchoice=choices->next; + delete choices; + choices=tmpchoice; + } + choices=newtopchoices; + + + // Parse file resources + if(GetLine("FILETBL")){ + table=GetCurrentLine(); + tablecount=GetParamCount(table); + } + for(int i=1;iname); + if(tmp){ + if(filenames->type=="P"){ + LogDebug("Autoloading background: %s", + filenames->name.c_str()); + SetBackground(tmp); + SDL_FreeSurface(tmp); + } + else if(filenames->type=="N"){ + LogDebug("Autosetting background: %s", + filenames->name.c_str()); + if(s_background){ + SDL_FreeSurface(s_background); + } + s_background=tmp; + SetBackground(tmp); + } + else{ + LogError("Invalid autoload resource: %s", + filenames->type.c_str()); + SDL_FreeSurface(tmp); + } + } + } + + // Get startindex + if(GetLine("MSGTBL")){ + table=GetCurrentLine(); + GetLine(GetParam(table,1)); + state=JASTSTATE_NORMAL; + } + + // Store name + scriptname=Script; + } + else{ + delete [] tbuffer; + } + } + } + else{ + LogError("Invalid script: %s",Script.c_str()); + } + return retval; +} + +/*! \brief Tags a main menu item as visible/hidden + * \param Index Index of menu item + * \param Visible Wheter to hide or show the item + * \param True if the item was found and configured + */ +bool EngineJAST::ShowMain(int Index,bool Visible){ + CHOICE_TYPE *vvptr=choices; + for(int i=1;vvptr && inext; + } + if(vvptr){ + vvptr->visible=Visible; + } + return vvptr; +} + +/*! \brief Tags a main menu item as visible/hidden + * \param Index Index of parent menu item + * \param SubIndex Index of menu item + * \param Visible Wheter to hide or show the item + * \param True if the item was found and configured + */ +bool EngineJAST::ShowSub(int Index,int SubIndex,bool Visible){ + bool retval=false; + CHOICE_TYPE *vvptr=choices; + for(int i=1;vvptr && inext; + } + if(vvptr){ + CHOICE_TYPE *nnptr=vvptr->sub; + for(int i=1;nnptr && inext; + } + if(nnptr){ +/* +if(Visible){ +LogTest("SHOW:%d.%d:%s",Index,SubIndex,nnptr->caption.c_str()); +} +else{ +LogTest("HIDE:%d.%d:%s",Index,SubIndex,nnptr->caption.c_str()); +} +*/ + + nnptr->visible=Visible; + retval=true; + } + } + return retval; +} + +/*! \brief Show choice/command selection + * \param Index Index of parent menu item (0 to show main menu) + * \return True if choices were successfully shown + */ +bool EngineJAST::ShowSelection(int Index){ + bool retval=false; + SDL_Rect rect=w_tv->GetPosition(); + rect.w=rect.w/3; + rect.h=rect.h/3; + Uint32 black=0x000000FF; + Uint32 white=0xFFFFFFFF; + w_sel=new Selection(this); + w_sel->Move(rect); + w_sel->Resize(500,66); + w_sel->SetFontSize(18); + w_sel->SetColors(white,black,black,white); + AddWidget(w_sel,VL_CHOICES); + if(Index<1){ + // Show main menu items + CHOICE_TYPE *vvptr=choices; + while(vvptr){ + if(vvptr->visible){ + retval=true; + w_sel->SetText(Unquote(vvptr->caption),rect,vvptr->index); + rect.x+=rect.w; + if(rect.x+rect.w>=w_tv->GetX()+w_tv->GetWidth()){ + rect.x=w_tv->GetX(); + rect.y=rect.y+rect.h; + } + } + vvptr=vvptr->next; + } + w_sel->SetFocusItem(choicemain); + } + else{ + // Show submenu items + CHOICE_TYPE *vvptr=choices; + while(vvptr){ + if(vvptr->index==Index){ + CHOICE_TYPE *nnptr=vvptr->sub; + if(!vvptr->visible){ + nnptr=0; + } + while(nnptr){ + if(nnptr->visible){ + retval=true; + uString c=Unquote(nnptr->caption); + w_sel->SetText(c,rect,(nnptr->index<<8)|vvptr->index); + rect.x+=rect.w; + if(rect.x+rect.w>=w_tv->GetX()+w_tv->GetWidth()){ + rect.x=w_tv->GetX(); + rect.y=rect.y+rect.h; + } + } + nnptr=nnptr->next; + } + } + vvptr=vvptr->next; + } + w_sel->SetFocusItem(choicesub); + } + w_tv->ClearText(); + state=JASTSTATE_SELECT; + return retval; +} + +void EngineJAST::EventSelect(int Selection){ + // Get menu name in order to identify storyline + uString mname; + uString sname; + if(Selection>0xFF){ + // Submenu + choicesub=Selection; + mname=EDL_Format("vv%d",Selection&0xFF); + sname=EDL_Format("nn%d",Selection>>8); + } + else{ + // Main menu + choicemain=Selection; + mname=EDL_Format("vv%d",Selection); + sname="-1"; + } + + // Get main menu object + CHOICE_TYPE *object=choices; + while(object && object->id!=mname){ + object=object->next; + } + + // Get sub menu object + if(object && sname!="-1"){ + object=object->sub; + while(object && object->id!=sname){ + object=object->next; + } + } + + // Assert a proper menu object + if(!object){ + LogError("Invalid menu selection: %d",Selection); + return; + } + + // Scan storylines for named items + uString msg; + int tablecount=0; + uString table; + if(GetLine("SCTBL")){ + table=GetCurrentLine(); + } + for(int j=0;!msg.length() && table.length();j++){ + // Parse commaseparated labels + tablecount=GetParamCount(table); + for(int i=1;!msg.length() && iBlend(surface,&s,&d); + SDL_FreeSurface(surface); + } + return Resource; +} + +bool EngineJAST::SetBackground(SDL_Surface *Resource){ + if(Resource){ + w_display->Blit(Resource,0,&r_display); + } + return Resource; +} + +bool EngineJAST::SetFrame(SDL_Surface *Resource){ + if(Resource){ + w_display->Blit(Resource); + } + return Resource; +} + +bool EngineJAST::EventBackgroundMouseRightUp(int X,int Y){ + // Show options dialog + EventGameDialog(VD_OPTIONS); + return true; +} + +bool EngineJAST::EventGameTick(){ + //if(state!=JASTSTATE_SELECT){ + if(state==JASTSTATE_WAITCLICK || state==JASTSTATE_PRESELECT){ + bool skip=keyok || keyctrl() || GetSkipmode(); + if(skip && w_tv->GetRemainingText()){ + w_tv->CompleteText(); + keyok=false; + } + else if(skip){ + w_tv->ClearText(); + if(state==JASTSTATE_PRESELECT){ + // Skip last message and show selection + state=JASTSTATE_SELECT; + ShowSelection(0); + } + else{ + // Normal text skip + state=JASTSTATE_NORMAL; + } + keyok=false; + } + } + return !(state==JASTSTATE_NORMAL); +} + +bool EngineJAST::EventGameProcess(){ + bool retval=true; + if(state==JASTSTATE_NORMAL && scriptindex && scriptindexSaveString("scriptname",scriptname); + save->SaveString("scriptlabel",scriptlabel); + save->SaveUint32("scriptindex",scriptindex); + save->SaveVector("variables",&vars); + + // Store graphics + SDL_Surface *screen=EDL_CreateSurface(NativeWidth(),NativeHeight()); + Paint(screen,VL_CHOICES); + save->SaveSurface("screen-thumb",screen,96,72); + Paint(screen,VL_CHARACTERS); + SDL_Rect rdisplay=r_display; + rdisplay.y+=w_display->GetY(); + SDL_Surface *sdisplay=EDL_CreateSurface(rdisplay.w,rdisplay.h); + EDL_BlitSurface(screen,&rdisplay,sdisplay,0); + save->SaveSurface("screen-display",sdisplay); + SDL_FreeSurface(screen); + SDL_FreeSurface(sdisplay); + + // Close up shop + save->Write(); + delete save; + return true; +} + +bool EngineJAST::EventLoad(int Index){ + bool retval=false; + Savegame *load=new Savegame(NativeID(),Index); + if(load->Read()){ + // Reload script + load->LoadString("scriptname",&scriptname); + LoadJASTScript(scriptname); + + // Reset data states + load->LoadVector("variables",&vars); + load->LoadString("scriptlabel",&scriptlabel); + load->LoadUint32("scriptindex",(Uint32*)&scriptindex); + + // Load graphics + SDL_Surface *tmps; + if(load->LoadSurface("screen-display",&tmps)){ + SetBackground(tmps); + SDL_FreeSurface(tmps); + } + } + return retval; +} + +uString EngineJAST::Unquote(uString Text){ + uString retval=Text; + if(Text.length()){ + if(Text[0]=='\'' && Text[Text.length()-1]=='\''){ + retval=Text.substr(1,Text.length()-2); + } + if(Text[0]=='\"' && Text[Text.length()-1]=='\"'){ + retval=Text.substr(1,Text.length()-2); + } + } + return retval; +} + +uString EngineJAST::PopString(DStack *Stack){ + uString retval; + uString *popped=(uString*)Stack->Pop(); + if(popped){ + retval=*popped; + delete popped; + } + return retval; +} + +bool EngineJAST::Interpret(DStack *Stack){ + bool retval=true; + uString cmd=PopString(Stack); + if(cmd=="" || cmd=="db" || cmd=="dw"){ + // Can be anything ... + } + else if(cmd[0]=='\"' || cmd[0]=='\''){ + // Print quoted text + cmd=Unquote(cmd); + for(unsigned int i=0;iPrintText(cmd); + } + else if(cmd=="cr"){ + // Newline + w_tv->PrintNewline(); + } + else if(cmd=="next"){ + // Wait for user input + state=JASTSTATE_WAITCLICK; + retval=false; + } + else if(cmd=="pause"){ + // Not supported for now (Should have a timed delay in the text) + } + else if(cmd=="bgm"){ + // Start BGM track + cmd=PopString(Stack); + if(cmd.length()==1){ + cmd=uString("0")+cmd; + } + PlayMusic(uString("SOS")+cmd); + } + else if(cmd=="flash"){ + // Flash a white + retval=false; + int cnt=PopString(Stack).to_int(); + SDL_Rect dst=w_display->GetPosition(); + SDL_Rect src={0,0,w_display->GetWidth(),w_display->GetHeight()}; + for(int i=0;iGetSurface(),src,100); + AddAnimation(white); + AddAnimation(real); + } + } + else if(cmd=="gata"){ + // The classic, and seemingly quintessential, shake screen effect.. + retval=false; + int cnt=PopString(Stack).to_int(); + //SDL_Surface *display=w_display->GetSurface(); + SDL_Surface *display=SDL_GetVideoSurface(); + SDL_Rect start={0,0,display->w,display->h}; + SDL_Rect stop={0,0,display->w,display->h}; + for(int i=0;iPeek()){ + vars.SetUint8(PopString(Stack).to_int(),0); + } + } + else{ + LogError("Invalid erase operation: %s",cmd.c_str()); + Stack->Flush(); + } + } + else if(cmd=="flg"){ + // Flag operation (Volatile flags) + cmd=PopString(Stack); + if(cmd=="f_copyi"){ + // Copy integer + int d=PopString(Stack).to_int(); + Uint8 v=PopString(Stack).to_int(); + vars.SetUint8(d,v); + } + else if(cmd=="f_and"){ + // And two operators + int d=PopString(Stack).to_int(); + int s1=PopString(Stack).to_int(); + int s2=PopString(Stack).to_int(); + int v1=vars.GetUint8(s1); + int v2=vars.GetUint8(s2); + vars.SetUint8(d,v1&v2); + } + else if(cmd=="f_mand"){ + // And multiple operators + PopString(Stack); + int d=PopString(Stack).to_int(); + int s=vars.GetUint8(d); + while(Stack->Peek()){ + int t=PopString(Stack).to_int(); + s&=vars.GetUint8(t); + } + vars.SetUint8(d,s); + } + else if(cmd=="f_exit"){ + // Stop executing block if var=0 + int s=PopString(Stack).to_int(); + s=vars.GetUint8(s); + if(s==0){ + if(scriptlabel=="M_EXIT" || !GetLine("M_EXIT")){ + state=JASTSTATE_PRESELECT; + retval=false; + } + } + } + else if(cmd=="f_jeq"){ + // Execute following line if NULL + int s=PopString(Stack).to_int(); + Uint8 v=vars.GetUint8(s); + if(v!=0){ + GetNextLine(); + } + } + else{ + LogError("Invalid flag operation: %s (%s)",cmd.c_str()); + Stack->Flush(); + } + } + else if(cmd=="g_flg"){ + // Flag operation (Persistent flags) + cmd=PopString(Stack); + if(cmd=="g_copyi"){ + // Copy intermediate + int d=PopString(Stack).to_int(); + Uint8 v=PopString(Stack).to_int(); + vars.SetUint8(d,v); + } + else if(cmd=="g_copyf"){ + // Copy flag + int d=PopString(Stack).to_int(); + Uint8 s=PopString(Stack).to_int(); + Uint8 v=vars.GetUint8(s); + vars.SetUint8(d,v); + } + else{ + LogError("Invalid gflag operation: %s (%s)",cmd.c_str()); + Stack->Flush(); + } + } + else if(cmd=="c_bld"){ + // Build choices + cmd=PopString(Stack); + int main=PopString(Stack).to_int(); + int sub=PopString(Stack).to_int(); + if(cmd=="c_v_on"){ + ShowMain(main,false); + } + else if(cmd=="c_v_off"){ + ShowMain(main,true); + } + else if(cmd=="c_n_on"){ + ShowSub(main,sub,false); + } + else if(cmd=="c_n_off"){ + ShowSub(main,sub,true); + } + else{ + LogError("Invalid choice operation: %s",cmd.c_str()); + Stack->Flush(); + } + } + else if(cmd=="buf"){ + // Blit cached background + cmd=PopString(Stack); + SetBackground(s_background); + } + else if(cmd=="sinario"){ + // Load next script + cmd=PopString(Stack); + cmd=Unquote(cmd); + LoadJASTScript(cmd); + Stack->Flush(); + } + else if(cmd=="0000h"){ + // Go to default exit or show command options + if(scriptlabel=="M_EXIT" || !GetLine("M_EXIT")){ + state=JASTSTATE_PRESELECT; + retval=false; + } + } + else if(cmd=="ani"){ + // We dont fucking *care* about eye animations!! + Stack->Flush(); + } + else if(cmd=="bak_init"){ + // Cache a background image + cmd=PopString(Stack); + cmd=Unquote(cmd); + if(s_background){ + SDL_FreeSurface(s_background); + } + s_background=LoadImage(cmd); + if(!s_background){ + LogError("Invalid backgound image: [%s]",cmd.c_str()); + Stack->Flush(); + } + } + else if(cmd=="b_o"){ + // Fill background with black + cmd=PopString(Stack); + SDL_Surface *s=EDL_CreateSurface(r_display.w,r_display.h); + SetBackground(s); + SDL_FreeSurface(s); + r_display.y+=w_display->GetY(); + SetTransition(&r_display); + r_display.y-=w_display->GetY(); + } + else if(cmd=="b_p1"){ + // Use effect to show cached background + cmd=PopString(Stack); + SetBackground(s_background); + r_display.y+=w_display->GetY(); + SetTransition(&r_display); + r_display.y-=w_display->GetY(); + } + else if(cmd=="e_cg"){ + // Load background graphics without caching it + uString fx=PopString(Stack); + uString fn=PopString(Stack); + fn=Unquote(fn); + SDL_Surface *s=LoadImage(fn); + SetBackground(s); + SDL_FreeSurface(s); + r_display.y+=w_display->GetY(); + SetTransition(&r_display); + r_display.y-=w_display->GetY(); + } + else if(cmd=="t_cg" || cmd=="t_cg1" || cmd=="k_cg" || cmd=="tu_cg"){ + // Load character graphics + uString base=PopString(Stack); + uString op1=PopString(Stack); + uString op2=PopString(Stack); + int x=PopString(Stack).to_int(); + PopString(Stack); + + LogTest("CG: %s %s %s %s %d",base.c_str(), + cmd.c_str(),op1.c_str(),op2.c_str(),x); + + // Debug paramers + if(cmd=="k_cg"){ + x=op2.to_int(); + op2=""; + } + + // Load base graphics + base=Unquote(base); + uString name=base; + op1=Unquote(op1); + if(op1!="0" && op1!="-1"){ + name=base+op1; + } + SDL_Surface *tmp=LoadImage(name); + if(tmp){ + SetCharacter(tmp,x); + SDL_FreeSurface(tmp); + } + else{ + LogError("Invalid character image: [%s]",name.c_str()); + Stack->Flush(); + } + + // Load overlay graphics + if(op2.length() && op2!="0" && op2!="-1"){ + op2=Unquote(op2); + name=base+op2; + tmp=LoadImage(name); + if(tmp){ + SetCharacter(tmp,x); + SDL_FreeSurface(tmp); + } + else{ + LogError("Invalid character image: [%s]",name.c_str()); + Stack->Flush(); + } + } + } + else if(cmd=="cg"){ + // Use graphics from resource list + cmd=PopString(Stack).c_str(); + int index=cmd.to_int(); + FILENAME_TYPE *filename=filenames; + for(int i=0;inext; + } + if(filename){ + SDL_Surface *tmp=LoadImage(filename->name); + if(tmp){ + if(filename->type=="P"){ + // Temporary background? + SetBackground(tmp); + SDL_FreeSurface(tmp); + } + else if(filename->type=="N"){ + // Consistent background? + if(s_background){ + SDL_FreeSurface(s_background); + } + s_background=tmp; + SetBackground(tmp); + } + else if(filename->type=="8"){ + // CG? + SetCharacter(tmp,0); + SDL_FreeSurface(tmp); + } + else{ + LogError("Invalid cg type: %s",filename->type.c_str()); + SDL_FreeSurface(tmp); + } + } + else{ + LogError("Invalid cg reference: %s",filename->name.c_str()); + Stack->Flush(); + } + } + else{ + LogError("Invalid cg index: %s",cmd.c_str()); + } + } + else if(cmd=="ef_set"){ + // Set flag + int d=PopString(Stack).to_int(); + int v=vars.GetUint8(d); + if(!v){ + vars.SetUint8(d,1); + } + } + else{ + if(GetLine(cmd)){ + // Check for labeled jumps + LogTest("Jumping to %s",cmd.c_str()); + } + else{ + LogError("UNKNOWN PARAMETER: %s",cmd.c_str()); + Stack->Flush(); + } + } + return retval; +} + + diff --git a/engines/vileVN/jast/jast.h b/engines/vileVN/jast/jast.h new file mode 100644 index 0000000000..7b1426314f --- /dev/null +++ b/engines/vileVN/jast/jast.h @@ -0,0 +1,120 @@ +/*! \class EngineJAST + * \brief JAST game engine + * + * The windy engine uses a wordcode interpreter to drive the game. Tbe kink + * with this system is that it allocates common routines in a different + * script. It also calls routines from both internal and external routines, + * making a stacking mechanism necesary for both handlers. + * + * This implementation covers this by accessing the "current script resource" + * from a set of pointers; These pointers can point to either the resources + * for common routines (ssxxxxx) or the currently loaded resource (lsxxxxx). + * + * The engine is currently rough on systemrelated commands, but works quite + * well using macros instead of the external methods (which holds most of the + * systemcalls). + * + * The JAST engine is not UNICODE compliant as it only supports three games. + */ +#ifndef _JAST_H_ +#define _JAST_H_ + +#include "../engine/evn.h" + +#define GETWORD(B) ((B)[0]|((B)[1]<<8)) + +class EngineJAST : public EngineVN { + private: + // Script data + uString scriptname; + uString scriptlabel; + Uint8 *scriptbuffer; + int scriptlength; + int scriptindex; + + // File resource database + struct FILENAME_TYPE { + uString type; //!< Filetype (Ex. P,N,numeric) + uString name; //!< Filename (Ex. MB02_1,) + FILENAME_TYPE *next; + }*filenames; + void AddFilename(uString Name,uString Type); + void ClearFilenames(); + + + // Label database + struct LABEL_TYPE { + uString caption; //!< Label (Typically M1, M2, etc) + int index; //!< Script index + LABEL_TYPE *next; + }*labels; + void AddLabel(uString Caption,int Index); + void ClearLabel(); + + // Choice management + struct CHOICE_TYPE { + uString id; //!< Textual ID (Typicall VVx and NNx) + uString caption; //!< Caption to display + int index; //!< Index (Main and sub separately) + bool visible; //!< Wether item should show + CHOICE_TYPE *sub; //!< Submenu (Null for none and subs) + CHOICE_TYPE *next; //!< Pointer for stacking + }*choices; //!< Head menu item + void AddChoice(uString ID); + void AddChoice(uString ID,uString SubID); + void ClearChoice(); + + // Widgets + Widget *w_display; + Textview *w_tv; + Selection *w_sel; + SDL_Rect r_display; + + SDL_Surface *s_background; //!< Caches background image + DVector vars; //!< Holds values + int choicemain, //!< Last chosen mainmenu index + choicesub; //!< Last chosen summenu index + + // Parsers + bool GetLine(uString Label); + uString GetCurrentLine(); + uString GetNextLine(); + int GetParamCount(uString Line); + uString GetParam(uString Line,int Index); + + // Santa's little helpers + uString PopString(DStack *Stack); + uString Unquote(uString Text); + bool Interpret(DStack *Stack); + + // State control + enum JAST_STATE { //!< State of engine + JASTSTATE_NORMAL, //!< Normal processing state + JASTSTATE_PRESELECT, //!< Show last message and then selection + JASTSTATE_SELECT, //!< Wait for user selection + JASTSTATE_WAITCLICK //!< Wait for user then return to normal + }state; + public: + EngineJAST(int Width,int Height); + ~EngineJAST(); + + // JAST Support methods + bool LoadJASTScript(uString Script); + bool SetFrame(SDL_Surface *Resource); + bool SetBackground(SDL_Surface *Resource); + bool SetCharacter(SDL_Surface *Resource,int X); + bool ShowSelection(int Index); + bool ShowMain(int Index,bool Visible); + bool ShowSub(int Index,int SubIndex,bool Visible); + + // Eventhandlers + virtual bool EventGameTick(); + virtual bool EventGameProcess(); + virtual bool EventBackgroundMouseRightUp(int X,int Y); + virtual void EventSelect(int Selection); + virtual bool EventSave(int Index); + virtual bool EventLoad(int Index); +}; + +#endif + diff --git a/engines/vileVN/jast/jumc.cpp b/engines/vileVN/jast/jumc.cpp new file mode 100644 index 0000000000..39a4bedffc --- /dev/null +++ b/engines/vileVN/jast/jumc.cpp @@ -0,0 +1,97 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "jumc.h" + +JUMC::JUMC(uString Path) : EngineJAST(640,480) { + // Add resources + AddImages(new ArchiveJAST(Path+"data/images.pck")); + AddImages(new ArchiveJAST(Path+"data/frames.pck")); + AddImages(new ArchiveJAST(Path+"data/common.pck")); + AddScripts(new ArchiveJAST(Path+"data/data.pck")); + AddBGM(new ArchiveFiles(Path+"music/*.mP3")); + + // Set unspecified title + title=JT_COMMON; + + // Load main menu + main=new JUMCMain(this); + AddWidget(main,VL_DIALOG); + EventGameDialog(VD_TITLE); +} + +JUMC::~JUMC(){ +} + +bool JUMC::StartGame(JUMC_TITLE Title){ + bool retval=false; + if(Title==JT_SOS){ + SDL_Surface *frame=LoadImage("soscls"); + title=Title; + SetFrame(frame); + LoadJASTScript("cs101"); + SDL_FreeSurface(frame); + retval=true; + } + if(Title==JT_3SIS){ + SDL_Surface *frame=LoadImage("siscls"); + title=Title; + SetFrame(frame); + LoadJASTScript("sk_101"); + SDL_FreeSurface(frame); + retval=true; + } + if(Title==JT_RUN){ + SDL_Surface *frame=LoadImage("runcls"); + title=Title; + SetFrame(frame); + LoadJASTScript("mt_0101"); + SDL_FreeSurface(frame); + retval=true; + } + return retval; +} + +void JUMC::EventGameDialog(VN_DIALOGS Dialog){ + if(VD_TITLE){ + StopMusic(); + main->SetVisible(true); + } + else{ + EngineVN::EventGameDialog(Dialog); + } +} + +const uString JUMC::NativeID(){ + switch(title){ + case JT_SOS: return "SOS"; + case JT_3SIS: return "3SIS"; + case JT_RUN: return "RUN"; + case JT_COMMON: return "JUMC"; + default: return "JUMC"; + }; +} + +const uString JUMC::NativeName(){ + switch(title){ + case JT_SOS: return "Season of the Sakura"; + case JT_3SIS: return "3 Sisters Story"; + case JT_RUN: return "Runaway City"; + case JT_COMMON: return "JAST USA Memorial Collection"; + default: return "JAST USA Memorial Collection"; + }; +} + + diff --git a/engines/vileVN/jast/jumc.h b/engines/vileVN/jast/jumc.h new file mode 100644 index 0000000000..a49cba2fff --- /dev/null +++ b/engines/vileVN/jast/jumc.h @@ -0,0 +1,35 @@ +#ifndef _JUMC_H_ +#define _JUMC_H_ + +#include "jast.h" +#include "jumcmain.h" + +// Declare game titles +enum JUMC_TITLE { //!< Enumerates game titles + JT_COMMON, //!< Common part + JT_SOS, //!< Season of Sakura + JT_3SIS, //!< 3 Sisters story + JT_RUN, //!< Runaway city +}; + + +class JUMC : public EngineJAST { + private: + // Identifiers + virtual const uString NativeID(); + virtual const uString NativeName(); + + // Override events + virtual void EventGameDialog(VN_DIALOGS Dialog); + + // Widgets + JUMCMain *main; + JUMC_TITLE title; + public: + JUMC(uString Path); + ~JUMC(); + bool StartGame(JUMC_TITLE Title); +}; + +#endif + diff --git a/engines/vileVN/jast/jumcmain.cpp b/engines/vileVN/jast/jumcmain.cpp new file mode 100644 index 0000000000..cb82874480 --- /dev/null +++ b/engines/vileVN/jast/jumcmain.cpp @@ -0,0 +1,175 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "jumcmain.h" +#include "jumc.h" + +JUMCMain::JUMCMain(JUMC *Engine) : DialogBase(Engine,false){ + // Load graphics + SDL_Surface *s_main=Engine->LoadImage("mainscreen"); + SDL_Surface *s_sos_dim=Engine->LoadImage("sosdim"); + SDL_Surface *s_sos_new=Engine->LoadImage("sosnew"); + SDL_Surface *s_sos_load=Engine->LoadImage("sosload"); + SDL_Surface *s_sos_cg=Engine->LoadImage("soscg"); + SDL_Surface *s_sis_dim=Engine->LoadImage("sisdim"); + SDL_Surface *s_sis_new=Engine->LoadImage("sisnew"); + SDL_Surface *s_sis_load=Engine->LoadImage("sisload"); + SDL_Surface *s_sis_cg=Engine->LoadImage("siscg"); + SDL_Surface *s_run_dim=Engine->LoadImage("rundim"); + SDL_Surface *s_run_new=Engine->LoadImage("runnew"); + SDL_Surface *s_run_load=Engine->LoadImage("runload"); + SDL_Surface *s_run_cg=Engine->LoadImage("runcg"); + SDL_Surface *s_gen_dim=Engine->LoadImage("gendim"); + SDL_Surface *s_gen_cg=Engine->LoadImage("gencg"); + SDL_Surface *s_gen_music=Engine->LoadImage("genmusic"); + SDL_Surface *s_gen_setup=Engine->LoadImage("gensetup"); + SDL_Surface *s_gen_exit=Engine->LoadImage("genexit"); + + // Configure base dialog + Move(0,40); + Resize(640,400); + Blit(s_main); + + // Runaway city + SDL_Rect r_run_new={10,90,305,32}; + SDL_Rect r_run_load={10,119,305,32}; + SDL_Rect r_run_cg={10,152,305,32}; + d_runaway=new Selection(Engine); + d_runaway->Move(10,50); + d_runaway->Resize(305,185); + //d_runaway->Blit(s_run_dim); + d_runaway->SetSurface(s_run_new,0,r_run_new,JI_RUNAWAY_NEW); + d_runaway->SetSurface(s_run_load,0,r_run_load,JI_RUNAWAY_LOAD); + d_runaway->SetSurface(s_run_cg,0,r_run_cg,JI_RUNAWAY_CG); + AddWidget(d_runaway); + + // Three sisters story + SDL_Rect r_sis_new={325,90,305,32}; + SDL_Rect r_sis_load={325,119,305,32}; + SDL_Rect r_sis_cg={325,152,305,32}; + d_sisters=new Selection(Engine); + d_sisters->Move(325,50); + d_sisters->Resize(305,185); + //d_sisters->Blit(s_sis_dim); + d_sisters->SetSurface(s_sis_new,0,r_sis_new,JI_SISTERS_NEW); + d_sisters->SetSurface(s_sis_load,0,r_sis_load,JI_SISTERS_LOAD); + d_sisters->SetSurface(s_sis_cg,0,r_sis_cg,JI_SISTERS_CG); + AddWidget(d_sisters); + + // Season of the sakura + SDL_Rect r_sos_new={10,295,305,32}; + SDL_Rect r_sos_load={10,324,305,32}; + SDL_Rect r_sos_cg={10,357,305,32}; + d_sakura=new Selection(Engine); + d_sakura->Move(10,245); + d_sakura->Resize(305,185); + //d_sakura->Blit(s_sos_dim); + d_sakura->SetSurface(s_sos_new,0,r_sos_new,JI_SAKURA_NEW); + d_sakura->SetSurface(s_sos_load,0,r_sos_load,JI_SAKURA_LOAD); + d_sakura->SetSurface(s_sos_cg,0,r_sos_cg,JI_SAKURA_CG); + AddWidget(d_sakura); + + // System menu + SDL_Rect r_gen_cg={326,254,305,48}; + SDL_Rect r_gen_music={326,301,305,48}; + SDL_Rect r_gen_setup={326,345,305,48}; + SDL_Rect r_gen_exit={326,392,305,48}; + d_system=new Selection(Engine); + d_system->Move(324,245); + d_system->Resize(305,185); + //d_system->Blit(s_gen_dim); + d_system->SetSurface(s_gen_cg,0,r_gen_cg,JI_SYSTEM_CG); + d_system->SetSurface(s_gen_music,0,r_gen_music,JI_SYSTEM_MUSIC); + d_system->SetSurface(s_gen_setup,0,r_gen_setup,JI_SYSTEM_SETUP); + d_system->SetSurface(s_gen_exit,0,r_gen_exit,JI_SYSTEM_EXIT); + AddWidget(d_system); + + // Delete temporary graphics + SDL_FreeSurface(s_main); + SDL_FreeSurface(s_sos_dim); + SDL_FreeSurface(s_sos_new); + SDL_FreeSurface(s_sos_load); + SDL_FreeSurface(s_sos_cg); + SDL_FreeSurface(s_sis_dim); + SDL_FreeSurface(s_sis_new); + SDL_FreeSurface(s_sis_load); + SDL_FreeSurface(s_sis_cg); + SDL_FreeSurface(s_run_dim); + SDL_FreeSurface(s_run_new); + SDL_FreeSurface(s_run_load); + SDL_FreeSurface(s_run_cg); + SDL_FreeSurface(s_gen_dim); + SDL_FreeSurface(s_gen_cg); + SDL_FreeSurface(s_gen_music); + SDL_FreeSurface(s_gen_setup); + SDL_FreeSurface(s_gen_exit); +} + +bool JUMCMain::InputOk(Widget *Object){ + JUMC *jengine=(JUMC*)engine; + bool retval=false; + bool t1=(Object==d_runaway); + bool t2=(Object==d_sisters); + bool t3=(Object==d_sakura); + bool t4=(Object==d_system); + if(t1 || t2 || t3 || t4){ + int result=((Selection*)Object)->GetFocusItem(); + if(result==JI_RUNAWAY_NEW){ + jengine->StartGame(JT_RUN); + SetVisible(false); + } + if(result==JI_SAKURA_NEW){ + jengine->StartGame(JT_SOS); + SetVisible(false); + } + if(result==JI_SISTERS_NEW){ + jengine->StartGame(JT_3SIS); + SetVisible(false); + } + if(result==JI_SYSTEM_EXIT){ + // Close application + jengine->EventGameShutdown(); + } + retval=true; + } + return retval; +} + +bool JUMCMain::FocusEnter(Widget *Object){ + SDL_Surface *tmp=0; + if(Object==d_runaway) tmp=engine->LoadImage("rundim"); + if(Object==d_sisters) tmp=engine->LoadImage("sisdim"); + if(Object==d_sakura) tmp=engine->LoadImage("sosdim"); + if(Object==d_system) tmp=engine->LoadImage("gendim"); + if(tmp){ + Object->Blit(tmp); + SDL_FreeSurface(tmp); + } + return false; +} + +bool JUMCMain::FocusLeave(Widget *Object){ + SDL_Surface *tmp=0; + if(Object==d_runaway) tmp=engine->LoadImage("runnorm"); + if(Object==d_sisters) tmp=engine->LoadImage("sisnorm"); + if(Object==d_sakura) tmp=engine->LoadImage("sosnorm"); + if(Object==d_system) tmp=engine->LoadImage("gennorm"); + if(tmp){ + Object->Blit(tmp); + SDL_FreeSurface(tmp); + } + return false; +} + diff --git a/engines/vileVN/jast/jumcmain.h b/engines/vileVN/jast/jumcmain.h new file mode 100644 index 0000000000..9a75188c68 --- /dev/null +++ b/engines/vileVN/jast/jumcmain.h @@ -0,0 +1,41 @@ +#ifndef _JUMCMAIN_H_ +#define _JUMCMAIN_H_ + +#include "../dialogs/selection.h" + +class JUMC; + +enum JUMC_ITEMS { + JI_RUNAWAY_NEW, + JI_RUNAWAY_LOAD, + JI_RUNAWAY_CG, + JI_SISTERS_NEW, + JI_SISTERS_LOAD, + JI_SISTERS_CG, + JI_SAKURA_NEW, + JI_SAKURA_LOAD, + JI_SAKURA_CG, + JI_SYSTEM_CG, + JI_SYSTEM_MUSIC, + JI_SYSTEM_SETUP, + JI_SYSTEM_EXIT +}; + +class JUMCMain : public DialogBase { + private: + // Dialog widgets + Selection *d_runaway; + Selection *d_sisters; + Selection *d_sakura; + Selection *d_system; + + // Override events + virtual bool InputOk(Widget *Object); + virtual bool FocusEnter(Widget *Object); + virtual bool FocusLeave(Widget *Object); + public: + JUMCMain(JUMC *Engine); +}; + +#endif + diff --git a/engines/vileVN/media/affmpeg.cpp b/engines/vileVN/media/affmpeg.cpp new file mode 100644 index 0000000000..0211834303 --- /dev/null +++ b/engines/vileVN/media/affmpeg.cpp @@ -0,0 +1,629 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "affmpeg.h" + +AudioFFMPEG::AudioFFMPEG() : AudioBuffer() { + // Initialize ffmpeg at first run + static bool init=false; + if(!init){ +#if LIBAVCODEC_VERSION_MAJOR<54 + avcodec_init(); +#endif + av_log_set_level(AV_LOG_WARNING); + av_log_set_callback(log_callback); + init=true; + } + + // Unset variables + ops=0; + pb=0; + framecache=0; + FormatContext=0; + stream=0; + index=-1; + mintime=0; + packetcache=0; + packetsize=0; + packettime=0; + resampler=0; + resamplebuffer=0; + decoded_frame=0; + + // Create objects + datalock=SDL_CreateMutex(); + framelock=SDL_CreateMutex(); +} + +AudioFFMPEG::~AudioFFMPEG(){ + Close(); + SDL_DestroyMutex(datalock); + SDL_DestroyMutex(framelock); + if(resamplebuffer){ + delete [] resamplebuffer; + } +} + +FFMPEG_AUDIO_FRAME::FFMPEG_AUDIO_FRAME(int Framesize,int64_t Time){ + buffer=(unsigned char*)av_malloc(Framesize); + size=Framesize; + pts=Time; +} + +FFMPEG_AUDIO_FRAME::FFMPEG_AUDIO_FRAME(int Framesize){ + buffer=(unsigned char*)av_malloc(Framesize); + size=Framesize; + pts=AV_NOPTS_VALUE ; +} + +FFMPEG_AUDIO_FRAME::~FFMPEG_AUDIO_FRAME(){ + av_free(buffer); +} + +// Implement reading from blobs +int AudioFFMPEG::read_callback(void *rwops,uint8_t *buf,int size){ + return ((RWops*)rwops)->Read(buf,size); +} + +// Implement writing from blobs +int AudioFFMPEG::write_callback(void *rwops,uint8_t *buf,int size){ + return ((RWops*)rwops)->Write(buf,size); +} + +// Implement seeking from blobs +int64_t AudioFFMPEG::seek_callback(void *rwops,int64_t offset,int whence){ + RWops *ops=(RWops*)rwops; + if(whence==AVSEEK_SIZE){ + return ops->Size(); + } + else{ + return ops->Seek(offset,whence); + } +} + +// Passes ffmpeg log output to our verbose output +void AudioFFMPEG::log_callback(void *ptr,int level,const char* fmt,va_list vl){ + const int size=255; + static char buffer1[size]; + static char buffer2[size]; + int cnt=vsnprintf(buffer1,size,fmt,vl); + if(cnt>1){ + buffer1[size-1]=0; + cnt=sprintf(buffer2,"FFMPEG: %s",buffer1); + if(cnt>1){ + buffer2[cnt-1]=0; + LogVerbose(buffer2); + } + } +} + +/*! \brief Reads a single packet from the source data + * \return Read packet or NULL at error or eof + */ +AVPacket *AudioFFMPEG::GetPacket(){ + AVPacket *pack=(AVPacket*)av_malloc(sizeof(AVPacket)); + av_init_packet(pack); + int read=av_read_frame(FormatContext,pack); + if(read<0){ + // End of file + av_free(pack); + pack=0; + } + else{ + // Try to read packet + if(av_dup_packet(pack)==0){ + if(pack->stream_index==index){ + return pack; + } + } + + // Read packet recursively + av_free_packet(pack); + pack=GetPacket(); + } + return pack; +} + +/*! \brief Reads and decodes one or more frames of audio + * \return True if any frames could be decoded + */ +bool AudioFFMPEG::GetFrame(){ + bool retval=false; + SDL_LockMutex(datalock); + if(FormatContext && stream && packetcache){ + // Get pack properties + uint64_t time=av_rescale(packettime, + stream->time_base.num, + stream->time_base.den); + if(time!=AV_NOPTS_VALUE && timecodec->skip_frame=AVDISCARD_ALL; + } + else{ + stream->codec->skip_frame=AVDISCARD_DEFAULT; + } + +#if LIBAVCODEC_VERSION_MAJOR>=54 + unsigned int psize=packetcache->size; + while(packetcache->size>0){ + int got_frame=0; + if(!decoded_frame){ + decoded_frame=avcodec_alloc_frame(); + if(!decoded_frame){ + LogError("Out of audio memory"); + break; + } + else{ + avcodec_get_frame_defaults(decoded_frame); + } + } + int len=avcodec_decode_audio4(stream->codec,decoded_frame, + &got_frame,packetcache); + if(len<0){ + LogError("Audio decoder error"); + break; + } + if(got_frame){ + int asize=av_samples_get_buffer_size(NULL, + stream->codec->channels, + decoded_frame->nb_samples, + stream->codec->sample_fmt,1); + if(asize>0){ + retval|=Process(time,decoded_frame->data[0],asize); + } + } + packetcache->size-=len; + packetcache->data+=len; + } + packetcache->size+=psize; + packetcache->data-=psize; + av_free_packet(packetcache); + packetcache=0; +#else + // \deprecated Legacy avcodec interface + if(packetsize>0){ + // Allocate aligned memory + int asize=FRAMESIZE*2; + DECLARE_ALIGNED(16,unsigned char,decodebuffer)[asize]; + memset(decodebuffer+AVCODEC_MAX_AUDIO_FRAME_SIZE, + 0,FF_INPUT_BUFFER_PADDING_SIZE); + + // Decode packet +#if LIBAVCODEC_VERSION_MAJOR>=52 + AVPacket tmppacket; + av_init_packet(&tmppacket); + tmppacket.data=packetcache->data+(packetcache->size-packetsize); + tmppacket.size=packetsize; + int len=avcodec_decode_audio3(stream->codec, + (int16_t*)&decodebuffer,&asize,&tmppacket); + av_free_packet(&tmppacket); +#else + int len=avcodec_decode_audio2(stream->codec, + (int16_t*)&decodebuffer,&asize, + packetcache->data+(packetcache->size-packetsize), + packetsize); +#endif + + // Verify results and update packetsize + if(len<=0){ + LogError("Error decoding audio frame"); + stream->codec->skip_frame=AVDISCARD_ALL; + av_free_packet(packetcache); + packetcache=0; + packetsize=0; + asize=0; + } + else{ + packetsize-=len; + } + + // Post-process and buffer up the decoded data + if(asize && stream->codec->skip_frame!=AVDISCARD_ALL){ + retval|=Process(time,decodebuffer,asize); + } + } + else{ + // Discard package + av_free_packet(packetcache); + packetcache=0; + packetsize=0; + } +#endif + } + + // Check if we need a new packet + if(FormatContext && !packetcache){ + if((packetcache=GetPacket())){ + packetsize=packetcache->size; + if(packetcache->dts==(unsigned int)AV_NOPTS_VALUE){ + if(packettime<(unsigned int)stream->start_time){ + packettime=stream->start_time; + } + packettime+=1000*packetcache->duration; + } + else{ + packettime=(packetcache->dts-stream->start_time)*1000; + } + } + } + + SDL_UnlockMutex(datalock); + return retval; +} + +/*! \brief Process decoded audio frames and move into audio queue + * \param Buffer Audio data + * \param Size Size of buffer + */ +bool AudioFFMPEG::Process(time_t Time,unsigned char *Buffer,unsigned int Size){ + bool retval=false; + int outsize=Cfg::Audio::Buffersize; + if(!framecache){ + framecache=new FFMPEG_AUDIO_FRAME(outsize,Time); + framecache->size=0; + } + + // Temporary (/Dirty) hack for mayclub + if(stream->codec->sample_fmt==0){ + stream->codec->channels=1; + } + + // Resample stream + unsigned char *outbuffer=Buffer; + if(resampler){ + if(!resamplebuffer){ + resamplebuffer=new Uint8[FRAMESIZE*2]; + } + int outchannels=Cfg::Audio::Channels; + int inchannels=stream->codec->channels; + int written=audio_resample(resampler, + (int16_t*)resamplebuffer, + (int16_t*)Buffer, + Size/(inchannels*2)); + + if(written>0){ + outbuffer=resamplebuffer; + Size=written*outchannels*2; + if(Size>FRAMESIZE*2){ + LogError("Buffer overflow while resampling"); + } + } + else{ + LogError("Failed to convert bitrate"); + } + } + + // Store frames as they are filled + int aoffset=0; + int space=outsize-framecache->size; + int size=Size; + while(space<=size){ + memcpy(framecache->buffer+framecache->size, + outbuffer+aoffset,space); + framecache->size=outsize; + SDL_LockMutex(framelock); + framebuffer.Queue(framecache); + SDL_UnlockMutex(framelock); + framecache=new FFMPEG_AUDIO_FRAME(outsize,Time); + framecache->size=0; + size-=space; + aoffset+=space; + space=outsize; + retval=true; + } + + // Store remaining data in framecache + if(size>0){ + memcpy(framecache->buffer+framecache->size, + outbuffer+aoffset,size); + framecache->size+=size; + } + return retval; +} + + +/*! \brief Closes and flushes all currently opened data + */ +void AudioFFMPEG::CloseData(){ + SDL_LockMutex(datalock); + if(decoded_frame){ + av_free(decoded_frame); + } + if(framecache){ + delete framecache; + framecache=0; + } + if(packetcache){ + av_free_packet(packetcache); + packetcache=0; + } + if(stream){ + avcodec_close(stream->codec); + stream=0; + } + if(resampler){ + audio_resample_close(resampler); + resampler=0; + } + if(FormatContext){ + // TODO: Loop through and close stream objects? + //avcodec_close(FormatContext->streams[i]); +#if LIBAVCODEC_VERSION_MAJOR>=54 + avformat_close_input(&FormatContext); +#else + av_close_input_stream(FormatContext); + FormatContext=0; +#endif + } + if(pb){ + unsigned char *b=pb->buffer; + pb->buffer=0; + // This is seriously fucked across versions of the upstream library. + // The IO stream might be closed automatically, but not necessarily + // and the dedicated close function segfaults. + //avio_close(pb); + free(pb); + free(b); + pb=0; + } + if(ops){ + delete ops; + ops=0; + } + stream=0; + index=-1; + mintime=0; + decoded_frame=0; + SDL_UnlockMutex(datalock); +} + +/*! \brief Closes and flushes all currently opened data + */ +void AudioFFMPEG::CloseFrames(){ + SDL_LockMutex(framelock); + FFMPEG_AUDIO_FRAME *frame; + while((frame=(FFMPEG_AUDIO_FRAME*)framebuffer.Pop())){ + delete frame; + } + SDL_UnlockMutex(framelock); +} + +/*! \brief Closes and flushes all currently opened data + */ +void AudioFFMPEG::Close(){ + CloseData(); + CloseFrames(); +} + +bool AudioFFMPEG::Seek(uint64_t Offset){ + bool retval=false; + SDL_LockMutex(datalock); + if(FormatContext){ + av_seek_frame(FormatContext,-1,0,AVSEEK_FLAG_BACKWARD); + mintime=0; + retval=true; + } + SDL_UnlockMutex(datalock); + return retval; +} + +/*! \brief Asserts that a sufficent number of frames are cached and ready + * \return True if anything was decoded + * + * This method must be called regularly, preferably from a traditional + * decoding thread. This method returning false means that the calling + * thread can relax for a while as the stream is emty or the buffer is + * full. + */ +bool AudioFFMPEG::Decode(){ + // Get current framebuffer count + bool retval=false; + SDL_LockMutex(framelock); + int c=framebuffer.Count(); + SDL_UnlockMutex(framelock); + if(c0){ + replays--; + } + Seek(0); + } + } + } + return retval; +} + +/*! \brief Mixes decoded data to the output audio stream + * + * This method should typically be called from within the applications audio + * callback. Cached frames should always be cached with the same bitrate and + * characteristics as the audio output, so the data can be copied directly + * without any further conversion. + */ +void AudioFFMPEG::Mix(unsigned char *Output,int Length,double Volume){ + SDL_LockMutex(framelock); + FFMPEG_AUDIO_FRAME *frame=(FFMPEG_AUDIO_FRAME*)framebuffer.Pop(); + SDL_UnlockMutex(framelock); + if(frame){ + // Mix audio data to output + int16_t *src=(int16_t*)frame->buffer; + int16_t *dest=(int16_t*)Output; + for(int i=0;i0x7FFF) d=0x7FFF; + if(t<-0x7FFF) d=0xFFFF; + *dest=d; + dest++; + src++; + } + + // Release frame + delete frame; + } +} + +/*! \brief Opens and identifies an audio resouce from a RWops source + * \param Resource Source data + * \return True if Resource was identified as a valid audio resource + */ +bool AudioFFMPEG::Open(RWops *Resource){ + // Close existing and copy input data + Close(); + SDL_LockMutex(datalock); + ops=new RWops(); + if(!ops->OpenRW(Resource,false)){ + LogError("Failed to copy blob"); + SDL_UnlockMutex(datalock); + Close(); + return false; + } + + // Create a custom stream io handler for the resource + unsigned int iosize=2048+FF_INPUT_BUFFER_PADDING_SIZE; + unsigned char *iobuffer=(unsigned char*)malloc(iosize); + memset(iobuffer,0,iosize); +#if LIBAVCODEC_VERSION_MAJOR>=54 + pb=avio_alloc_context(iobuffer,iosize,0,ops, + read_callback,write_callback,seek_callback); +#else + pb=(ByteIOContext*)malloc(sizeof(ByteIOContext)); + memset(pb,0,sizeof(ByteIOContext)); + init_put_byte(pb,iobuffer,iosize,0,ops, + read_callback,write_callback,seek_callback); +#endif + + // Probe input format manually + AVProbeData probe_data; + probe_data.filename="blob"; + int probesize=(1024*4)+AVPROBE_PADDING_SIZE; + if(ops->Size()Size()+AVPROBE_PADDING_SIZE; + } + probe_data.buf_size=probesize-4; + probe_data.buf=(uint8_t*)malloc(probesize); + memset(probe_data.buf,0,probesize); + ops->Read(probe_data.buf,probesize); + ops->Seek(0,SEEK_SET); + AVInputFormat *fmt=av_probe_input_format(&probe_data,1); + free(probe_data.buf); + probe_data.buf=0; + if (!fmt){ + LogVerbose("FFMPEG could not identify unknown media"); + SDL_UnlockMutex(datalock); + Close(); + return false; + } + fmt->flags|=AVFMT_NOFILE; + // TODO: Free fmt at some point? + +#if LIBAVCODEC_VERSION_MAJOR>=54 + if(!FormatContext){ + FormatContext=avformat_alloc_context(); + } + FormatContext->pb=pb; + if(avformat_open_input(&FormatContext,"RWops",fmt,0)!=0){ +#else + if(av_open_input_stream(&FormatContext,pb,"RWops",fmt,0)!=0){ +#endif + LogError("FFMPEG failed to open audio stream"); + SDL_UnlockMutex(datalock); + Close(); + return false; + } + + // retrieve format information +#if LIBAVCODEC_VERSION_MAJOR>=54 + if(avformat_find_stream_info(FormatContext,NULL)<0){ +#elif LIBAVCODEC_VERSION_MAJOR>=52 + if(av_find_stream_info(FormatContext)<0){ +#else + if(avformat_find_stream_info(FormatContext,NULL)<0){ +#endif + LogError("FFMPEG could not retrieve file info for stream"); + SDL_UnlockMutex(datalock); + Close(); + return false; + } + + // Select first audio stream, discard all others + bool retval=false; + for(unsigned int i=0;!retval && inb_streams;i++){ + FormatContext->streams[i]->discard=AVDISCARD_ALL; +#if LIBAVCODEC_VERSION_MAJOR>=53 + enum AVMediaType type=FormatContext->streams[i]->codec->codec_type; + if(type==AVMEDIA_TYPE_AUDIO){ +#else + enum CodecType type=FormatContext->streams[i]->codec->codec_type; + if(type==CODEC_TYPE_AUDIO){ +#endif + // Try to find a decoder for this stream + enum CodecID id=FormatContext->streams[i]->codec->codec_id; + AVCodec *codec=avcodec_find_decoder(id); + if(!codec){ + LogError("Could not find audio codec"); + } +#if LIBAVCODEC_VERSION_MAJOR>53 + else if(avcodec_open2(FormatContext->streams[i]->codec,codec,NULL)<0) +#else + else if(avcodec_open(FormatContext->streams[i]->codec,codec)<0) +#endif + { + LogError("Failed to open audio codec"); + } + else{ + // Cache stream properties + stream=FormatContext->streams[i]; + stream->discard=AVDISCARD_DEFAULT; + bool resample=false; + resample|=(stream->codec->sample_rate!=Cfg::Audio::Frequency); + resample|=(stream->codec->channels!=Cfg::Audio::Channels); + resample|=(stream->codec->sample_fmt!=AV_SAMPLE_FMT_S16); + if(resample){ + resampler=av_audio_resample_init( + Cfg::Audio::Channels, + stream->codec->channels, + (int)Cfg::Audio::Frequency, + (int)stream->codec->sample_rate, + AV_SAMPLE_FMT_S16, + stream->codec->sample_fmt, + 16,10,0,1.0); + if(!resampler){ + LogError("Failed to load ffmpeg resampling context"); + } + } + LogVerbose("Opened ffmpeg audio (%d channels,%d Hz,%d bps)", + stream->codec->channels, + stream->codec->sample_rate, + stream->codec->bit_rate); + retval=true; + index=i; + } + } + } + + // Check if any streams were found + SDL_UnlockMutex(datalock); + if(!retval){ + Close(); + } + return retval; +} + diff --git a/engines/vileVN/media/affmpeg.h b/engines/vileVN/media/affmpeg.h new file mode 100644 index 0000000000..a2e9641f59 --- /dev/null +++ b/engines/vileVN/media/affmpeg.h @@ -0,0 +1,83 @@ +/*! \class AudioFFMPEG + * \brief AudioFFMPEG implements libav/ffmpeg on top of a AudioBuffer object. + */ + +#ifndef _AFFMPEG_H_ +#define _AFFMPEG_H_ + +// Some compiler trickery before including c library files +#ifndef INT64_C +#define INT64_C(c) (c ## LL) +#endif +#ifndef UINT64_C +#define UINT64_C(c) (c ## ULL) +#endif +extern "C" { +#include +#include +#include +#include +} + +// Base include +#include "audio.h" +#include "dstack.h" + +#define FRAMESIZE AVCODEC_MAX_AUDIO_FRAME_SIZE+FF_INPUT_BUFFER_PADDING_SIZE + +struct FFMPEG_AUDIO_FRAME { + FFMPEG_AUDIO_FRAME(int Framesize,int64_t Time); + FFMPEG_AUDIO_FRAME(int Framesize); + ~FFMPEG_AUDIO_FRAME(); + unsigned char *buffer; + unsigned int size; + int64_t pts; +}; + +class AudioFFMPEG : public AudioBuffer{ + private: + // Callbacks and utilities + static void log_callback(void *ptr,int lvl,const char *fmt,va_list vl); + static int read_callback(void *rwops,uint8_t *buf,int size); + static int write_callback(void *rwops,uint8_t *buf,int size); + static int64_t seek_callback(void *rwops,int64_t offset,int whence); + AVPacket *GetPacket(); + bool GetFrame(); + bool Seek(uint64_t Offset); + +#if LIBAVCODEC_VERSION_MAJOR>=53 + AVIOContext *pb; //!< Custom IO interface + AVFrame *decoded_frame; +#else + ByteIOContext *pb; //!< Custom IO interface +#endif + RWops *ops; //!< Holds source data + DStack framebuffer; //!< Stacks formatted frames + SDL_mutex *datalock; //!< Mutex for controldata + SDL_mutex *framelock; //!< Mutex for framebuffer + AVFormatContext *FormatContext; //!< Holds FFMPEG data + AVStream *stream; //!< Audio stream to decode + ReSampleContext *resampler; //!< Context for resampling output + AVPacket *packetcache; //!< Intermediary packet + FFMPEG_AUDIO_FRAME *framecache; //!< Intermediary frame + Uint8 *resamplebuffer; //!< Buffer for resampling data + uint64_t packettime; //!< Time of intermediary packet + uint64_t mintime; //!< Min timestamp to decode + int packetsize; //!< Size of intermediary packet + int index; //!< Index of audio stream + bool Process(time_t Time, + unsigned char *Buffer, + unsigned int Size); + void CloseData(); + void CloseFrames(); + public: + AudioFFMPEG(); + ~AudioFFMPEG(); + virtual bool Open(RWops *Resource); + virtual void Mix(unsigned char *Buffer,int Length,double Volume); + virtual bool Decode(); + virtual void Close(); +}; + +#endif + diff --git a/engines/vileVN/media/afluid.cpp b/engines/vileVN/media/afluid.cpp new file mode 100644 index 0000000000..06364ead9e --- /dev/null +++ b/engines/vileVN/media/afluid.cpp @@ -0,0 +1,241 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "afluid.h" + +AudioFluid::AudioFluid(){ + datalock=SDL_CreateMutex(); + framelock=SDL_CreateMutex(); + midisize=0; + midibuffer=0; + settings=0; + synth=0; + player=0; + + // Reroute fluidsynth messages + fluid_set_log_function(FLUID_PANIC,log,this); + fluid_set_log_function(FLUID_ERR,log,this); + fluid_set_log_function(FLUID_WARN,log,this); + fluid_set_log_function(FLUID_INFO,log,this); +} + +AudioFluid::~AudioFluid(){ + Close(); + SDL_DestroyMutex(datalock); + SDL_DestroyMutex(framelock); +} + +FLUID_FRAME::FLUID_FRAME(unsigned char *Buffer){ + buffer=Buffer; +} + +FLUID_FRAME::~FLUID_FRAME(){ + delete [] buffer; +} + +/*! \brief Passes Fluidsynth log messages back to ViLE + * \param Level Severity of the message + * \param Message Log message to dispatch + * \param Data Callback object (Not used) + */ +void AudioFluid::log(int Level,char *Message,void *Data){ + uString msg="FLUIDSYNTH: "; + if(Level==FLUID_PANIC || Level==FLUID_ERR){ + LogError(msg+Message); + } + else{ + LogVerbose(msg+Message); + } +} + +/*! \brief Open a MIDI track using a RWops + * \param Resource The RWops resource to open + * \return True if resource was successfully opened + */ +bool AudioFluid::Open(RWops *Resource){ + // Drop existing + bool retval=false; + uString sf=Cfg::Audio::Soundfont; + Close(); + SDL_LockMutex(datalock); + if(!sf.length() || !EDL_ReadableFile(sf)){ + LogVerbose("No MIDI Soundfont"); + } + else if(!Resource || Resource->Size()<16 || Resource->Size()>1024*1000){ + LogError("Invalid fluidsynth input data (%d bytes)", + Resource?Resource->Size():0); + } + else if(!(settings=new_fluid_settings())){ + LogError("Failed to load fluidsynth settings"); + } + else if(!(synth=new_fluid_synth(settings))){ + LogError("Failed to load fluidsynth synthesizer"); + } + else if(!(player=new_fluid_player(synth))){ + LogError("Failed to load fluidsynth player"); + } + else if((fluid_synth_sfload(synth,sf.c_str(),1)==FLUID_FAILED)){ + LogError("Failed to load fluidsynth font: %s",sf.c_str()); + } + else{ + double freq=Cfg::Audio::Frequency; + fluid_settings_setnum(settings,"synth.sample-rate",freq); + //fluid_settings_setnum(settings,"synth.verbose",1); + //fluid_settings_setnum(settings,"synth.gain",0.8); + Resource->Seek(0,SEEK_SET); + midisize=Resource->Size(); + midibuffer=new unsigned char[midisize]; + if(Resource->Read(midibuffer,midisize)<(int)midisize){ + LogError("Data was not readable"); + } + else if(fluid_player_add_mem(player,midibuffer,midisize)!=FLUID_OK){ + LogError("Failed to open MIDI data"); + } + else{ + LogVerbose("Opened %d bytes of fluidsynth data",midisize); + fluid_player_play(player); + retval=true; + } + } + + // Drop all objects if we failed + if(!retval){ + if(player){ + fluid_player_stop(player); + delete_fluid_player(player); + player=0; + } + if(synth){ + delete_fluid_synth(synth); + synth=0; + } + if(settings){ + delete_fluid_settings(settings); + settings=0; + } + if(midibuffer){ + delete [] midibuffer; + midibuffer=0; + midisize=0; + } + } + SDL_UnlockMutex(datalock); + return retval; +} + +/*! \brief Write synthesized data to framebuffer + * \return True if anything was decoded + * + * This is called from the engine audio decoder thread, checks the current + * framebuffer and loads more data if appropriate. Does nothing unless a + * valid MIDI track is loaded. + */ +bool AudioFluid::Decode(){ + bool retval=false; + SDL_LockMutex(datalock); + if(player && !fluid_player_get_status(player)){ + if(replays==0){ + SDL_UnlockMutex(datalock); + Close(); + SDL_LockMutex(datalock); + } + else{ + if(replays>0){ + replays--; + } + fluid_player_play(player); + } + } + if(player){ + SDL_LockMutex(framelock); + int c=framebuffer.Count(); + SDL_UnlockMutex(framelock); + if(cbuffer; + int16_t *dest=(int16_t*)Buffer; + for(int i=0;i0x7FFF) d=0x7FFF; + if(t<-0x7FFF) d=0xFFFF; + *dest=d; + dest++; + src++; + } + delete frame; + } +} + +/*! \brief Stops any audio and releases all resources + */ +void AudioFluid::Close(){ + SDL_LockMutex(datalock); + if(player){ + fluid_player_stop(player); + delete_fluid_player(player); + player=0; + } + if(synth){ + delete_fluid_synth(synth); + synth=0; + } + if(settings){ + delete_fluid_settings(settings); + settings=0; + } + if(midibuffer){ + delete [] midibuffer; + midibuffer=0; + midisize=0; + } + SDL_UnlockMutex(datalock); + SDL_LockMutex(framelock); + FLUID_FRAME *frame; + while((frame=(FLUID_FRAME*)framebuffer.Pop())){ + delete frame; + } + SDL_UnlockMutex(framelock); +} + + diff --git a/engines/vileVN/media/afluid.h b/engines/vileVN/media/afluid.h new file mode 100644 index 0000000000..b6f55c3583 --- /dev/null +++ b/engines/vileVN/media/afluid.h @@ -0,0 +1,39 @@ +/*! \class AudioFluid + * \brief AudioFluid implements Fluidsynth on top of a AudioBuffer object. + */ + +#ifndef _AFLUID_H_ +#define _AFLUID_H_ + +#include "audio.h" +#include "dstack.h" +#include + +struct FLUID_FRAME { + FLUID_FRAME(unsigned char *Buffer); + ~FLUID_FRAME(); + unsigned char *buffer; +}; + +class AudioFluid : public AudioBuffer{ + private: + static void log(int,char *,void*); //!< Callback for fluidsynth log + DStack framebuffer; //!< Stacks formatted frames + SDL_mutex *datalock; //!< Mutex for controldata + SDL_mutex *framelock; //!< Mutex for framebuffer + fluid_settings_t *settings; //!< Fluidsynth settings + fluid_synth_t *synth; //!< Fluidsynth synthesizer + fluid_player_t *player; //!< Fluidsynth player + unsigned char *midibuffer; //!< Buffer to MIDI data + unsigned int midisize; //!< Size of MIDI data + public: + AudioFluid(); + ~AudioFluid(); + virtual bool Open(RWops *Resource); + virtual void Mix(unsigned char *Buffer,int Length,double Volume); + virtual bool Decode(); + virtual void Close(); +}; + +#endif + diff --git a/engines/vileVN/media/audio.cpp b/engines/vileVN/media/audio.cpp new file mode 100644 index 0000000000..63807ef66e --- /dev/null +++ b/engines/vileVN/media/audio.cpp @@ -0,0 +1,41 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "audio.h" + +AudioBuffer::AudioBuffer(){ + replays=0; + playing=false; +} + +AudioBuffer::~AudioBuffer(){ +} + +void AudioBuffer::SetPlaying(bool Playing){ + playing=Playing; +} + +void AudioBuffer::SetReplays(int Replays){ + replays=Replays; +} + +bool AudioBuffer::GetPlaying(){ + return playing; +} + +int AudioBuffer::GetReplays(){ + return replays; +} + diff --git a/engines/vileVN/media/audio.h b/engines/vileVN/media/audio.h new file mode 100644 index 0000000000..a3d4cf97f0 --- /dev/null +++ b/engines/vileVN/media/audio.h @@ -0,0 +1,37 @@ +/*! \class AudioBuffer + * \brief AudioBuffer defines a generic audio decoder object. + * + * AudioBuffer is the generic audio interface. EngineMixer loads and drives + * a derived object which provides a buffered audio feed through the virtual + * interface. + */ + +#ifndef _AUDIO_H_ +#define _AUDIO_H_ + +#include "../res/rwops.h" +#include "../common/log.h" + +class AudioBuffer { + protected: + bool playing; //!< Wether resource is currently playing + int replays; //!< How many times the resource should play + public: + AudioBuffer(); + virtual ~AudioBuffer(); + + // Audio interface + virtual void SetPlaying(bool Playing); + virtual void SetReplays(int Replays); + virtual bool GetPlaying(); + virtual int GetReplays(); + + // Engine interface + virtual bool Open(RWops *Resource)=0; + virtual void Mix(unsigned char *Buffer,int Length,double Volume)=0; + virtual bool Decode()=0; + virtual void Close()=0; +}; + +#endif + diff --git a/engines/vileVN/media/vffmpeg.cpp b/engines/vileVN/media/vffmpeg.cpp new file mode 100644 index 0000000000..042ccd9ed1 --- /dev/null +++ b/engines/vileVN/media/vffmpeg.cpp @@ -0,0 +1,539 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "vffmpeg.h" + +VideoFFMPEG::VideoFFMPEG() : VideoBuffer() { + // Unset variables + screen=SDL_GetVideoSurface(); + yuycontext=0; + rgbcontext=0; + ops=0; + pb=0; + FormatContext=0; + stream=0; + index=-1; + mintime=0; + packetcache=0; + packetsize=0; + packettime=0; + dframe=0; + + // Create objects + datalock=SDL_CreateMutex(); + framelock=SDL_CreateMutex(); +} + +VideoFFMPEG::~VideoFFMPEG(){ + Close(); + SDL_DestroyMutex(datalock); + SDL_DestroyMutex(framelock); +} + +FFMPEG_VIDEO_FRAME::FFMPEG_VIDEO_FRAME(){ + overlay=0; + surface=0; + pts=0; +} + +FFMPEG_VIDEO_FRAME::~FFMPEG_VIDEO_FRAME(){ + if(surface){ + SDL_FreeSurface(surface); + } + if(overlay){ + SDL_FreeYUVOverlay(overlay); + } +} + +// Implement reading from blobs +int VideoFFMPEG::read_callback(void *rwops,uint8_t *buf,int size){ + return ((RWops*)rwops)->Read(buf,size); +} + +// Implement writing from blobs +int VideoFFMPEG::write_callback(void *rwops,uint8_t *buf,int size){ + return ((RWops*)rwops)->Write(buf,size); +} + +// Implement seeking from blobs +int64_t VideoFFMPEG::seek_callback(void *rwops,int64_t offset,int whence){ + RWops *ops=(RWops*)rwops; + if(whence==AVSEEK_SIZE){ + return ops->Size(); + } + else{ + return ops->Seek(offset,whence); + } +} + +void VideoFFMPEG::Close(){ + CloseData(); + CloseFrames(); +} + +/*! \brief Closes and flushes all currently opened data + */ +void VideoFFMPEG::CloseFrames(){ + SDL_LockMutex(framelock); + FFMPEG_VIDEO_FRAME *frame; + while((frame=(FFMPEG_VIDEO_FRAME*)framebuffer.Pop())){ + delete frame; + } + SDL_UnlockMutex(framelock); +} + +void VideoFFMPEG::CloseData(){ + SDL_LockMutex(datalock); + if(dframe){ + av_free(dframe); + dframe=0; + } + if(packetcache){ + av_free_packet(packetcache); + packetcache=0; + } + if(stream){ + avcodec_flush_buffers(stream->codec); + avcodec_close(stream->codec); + stream=0; + } + if(yuycontext){ + sws_freeContext(yuycontext); + yuycontext=0; + } + if(rgbcontext){ + sws_freeContext(rgbcontext); + rgbcontext=0; + } + if(FormatContext){ + // TODO: Loop through and close stream objects? + //avcodec_close(FormatContext->streams[i]); +#if LIBAVCODEC_VERSION_MAJOR>=54 + avformat_close_input(&FormatContext); +#else + av_close_input_stream(FormatContext); + FormatContext=0; +#endif + } + if(pb){ + // See AudioFFMPEG implementation for details on this nightmare + unsigned char *b=pb->buffer; + pb->buffer=0; + //avio_close(pb); + free(pb); + free(b); + pb=0; + } + if(ops){ + delete ops; + ops=0; + } + stream=0; + index=-1; + mintime=0; + SDL_UnlockMutex(datalock); +} + +/*! \brief Asserts that a sufficent number of frames are cached and ready + * \return True if anything was decoded + * + * This method must be called regularly, preferably from a traditional + * decoding thread. + */ +bool VideoFFMPEG::Decode(){ + // Get current framebuffer count + bool retval=false; + SDL_LockMutex(framelock); + int c=framebuffer.Count(); + SDL_UnlockMutex(framelock); + if(coverlay){ + SDL_Rect r={0,0,screen->w,screen->h}; + SDL_DisplayYUVOverlay(frame->overlay,&r); + } + if(frame->surface){ + SDL_BlitSurface(frame->surface,0,screen,0); + SDL_Flip(screen); + } + delete frame; + } + return frame || FormatContext; +} + +/*! \brief Opens and identifies an audio resouce from a RWops source + * \param Resource Source data + * \return True if Resource was identifies as a valid audio resource + */ +bool VideoFFMPEG::Open(RWops *Resource){ + // Close existing and copy input data + Close(); + SDL_LockMutex(datalock); + ops=new RWops(); + if(!ops->OpenRW(Resource,false)){ + LogError("Failed to copy blob"); + SDL_UnlockMutex(datalock); + Close(); + return false; + } + + // Probe input format manually + AVProbeData probe_data; + probe_data.filename="blob"; + int probesize=1024*4; + if(ops->Size()Size(); + } + probe_data.buf_size=probesize+AVPROBE_PADDING_SIZE; + probe_data.buf=(uint8_t*)malloc(probesize+AVPROBE_PADDING_SIZE); + memset(probe_data.buf+probesize,0,AVPROBE_PADDING_SIZE); + ops->Seek(0,SEEK_SET); + ops->Read(probe_data.buf,probesize); + ops->Seek(0,SEEK_SET); + AVInputFormat *fmt=av_probe_input_format(&probe_data,1); + free(probe_data.buf); + probe_data.buf=0; + if (!fmt){ + LogVerbose("FFMPEG could not identify unknown media"); + SDL_UnlockMutex(datalock); + Close(); + return false; + } + //fmt->flags|=AVFMT_NOFILE; + // TODO: Free fmt at some point? + + + // Create a custom stream io handler for the resource +#if LIBAVCODEC_VERSION_MAJOR<54 + pb=(ByteIOContext*)malloc(sizeof(ByteIOContext)); + memset(pb,0,sizeof(ByteIOContext)); +#endif + unsigned int iosize=2048+FF_INPUT_BUFFER_PADDING_SIZE; + unsigned char *iobuffer=(unsigned char*)malloc(iosize); + memset(iobuffer,0,iosize); +#if LIBAVCODEC_VERSION_MAJOR>=54 + pb=avio_alloc_context(iobuffer,iosize,0,ops, + read_callback,write_callback,seek_callback); + if(!pb){ + LogError("FFMPEG failed to open video context buffer"); + SDL_UnlockMutex(datalock); + Close(); + return false; + } +#else + init_put_byte(pb,iobuffer,iosize,0,ops, + read_callback,write_callback,seek_callback); +#endif + + +#if LIBAVCODEC_VERSION_MAJOR>=54 + if(!FormatContext){ + FormatContext=avformat_alloc_context(); + } + FormatContext->pb=pb; + if(avformat_open_input(&FormatContext,"RWops",fmt,0)<0){ +#else + if(av_open_input_stream(&FormatContext,pb,"RWops",fmt,0)!=0){ +#endif + LogError("FFMPEG failed to open video stream"); + SDL_UnlockMutex(datalock); + Close(); + return false; + } + + // retrieve format information +#if LIBAVCODEC_VERSION_MAJOR>=54 + if(avformat_find_stream_info(FormatContext,NULL)<0){ +#elif LIBAVCODEC_VERSION_MAJOR>=52 + if(av_find_stream_info(FormatContext)<0){ +#else + if(avformat_find_stream_info(FormatContext,NULL)<0){ +#endif + LogError("FFMPEG could not retrieve file info for stream"); + SDL_UnlockMutex(datalock); + Close(); + return false; + } + + // Select first audio stream, discard all others + bool retval=false; + for(unsigned int i=0;!retval && inb_streams;i++){ + FormatContext->streams[i]->discard=AVDISCARD_ALL; +#if LIBAVCODEC_VERSION_MAJOR>=53 + enum AVMediaType type=FormatContext->streams[i]->codec->codec_type; + if(type==AVMEDIA_TYPE_VIDEO){ +#else + enum CodecType type=FormatContext->streams[i]->codec->codec_type; + if(type==CODEC_TYPE_VIDEO){ +#endif + // Try to find a decoder for this stream + enum CodecID id=FormatContext->streams[i]->codec->codec_id; + AVCodec *codec=avcodec_find_decoder(id); + if(!codec){ + LogError("Could not find video codec"); + } +#if LIBAVCODEC_VERSION_MAJOR>53 + else if(avcodec_open2(FormatContext->streams[i]->codec,codec,NULL)<0) +#else + else if(avcodec_open(FormatContext->streams[i]->codec,codec)<0) +#endif + { + LogError("Failed to open video codec"); + } + else{ + // Cache stream properties + stream=FormatContext->streams[i]; + stream->discard=AVDISCARD_DEFAULT; + dframe=avcodec_alloc_frame(); + screen=SDL_GetVideoSurface(); + LogVerbose("Opened ffmpeg video"); + retval=true; + index=i; + } + } + } + + // Check if any streams were found + SDL_UnlockMutex(datalock); + if(!retval){ + Close(); + } + return retval; +} + + +/*! \brief Returns the frame rate of the stream as a fraction. + * \returns The result of nominator / denominator + */ +double VideoFFMPEG::Framerate(){ + if(stream && stream->codec){ + return stream->r_frame_rate.num / stream->r_frame_rate.den; + } + else{ + return 0; + } +} + + +/*! \brief Reads a single packet from the source data + * \return Read packet or NULL at error or eof + */ +AVPacket *VideoFFMPEG::GetPacket(){ + AVPacket *pack=(AVPacket*)av_malloc(sizeof(AVPacket)); + av_init_packet(pack); + int read=av_read_frame(FormatContext,pack); + if(read<0){ + // End of file + av_free(pack); + pack=0; + } + else{ + // Try to read packet + if(av_dup_packet(pack)==0){ + if(pack->stream_index==index){ + return pack; + } + } + + // Read packet recursively + av_free_packet(pack); + pack=GetPacket(); + } + return pack; +} + +/*! \brief Reads a single frame from the video stream + * \return False at EOF or error + */ +bool VideoFFMPEG::GetFrame(){ + bool retval=false; + SDL_LockMutex(datalock); + if(FormatContext && stream && packetcache){ + // Get pack properties + uint64_t time=av_rescale(packettime, + stream->time_base.num, + stream->time_base.den); + if(time!=AV_NOPTS_VALUE && timecodec->skip_frame=AVDISCARD_ALL; + } + else{ + stream->codec->skip_frame=AVDISCARD_DEFAULT; + } + + if(packetsize>0){ + // Decode data from stream + int gotframe=0; +#if ( ( LIBAVCODEC_VERSION_MAJOR <= 52 ) && ( LIBAVCODEC_VERSION_MINOR <= 20 ) ) + int used=avcodec_decode_video(stream->codec,dframe,&gotframe, + pack->data,pack->size); +#else + AVPacket p; + av_init_packet(&p); + p.data=packetcache->data+(packetcache->size-packetsize); + p.size=packetsize; + int used=avcodec_decode_video2(stream->codec,dframe,&gotframe,&p); +#endif + if(used<0){ + LogError("Error decoding video frame"); + stream->codec->skip_frame=AVDISCARD_ALL; + av_free_packet(packetcache); + packetcache=0; + packetsize=0; + gotframe=0; + } + else{ + packetsize-=used; + } + + // Post-process and buffer up decoded data + if(gotframe && stream->codec->skip_frame!=AVDISCARD_ALL){ + // Create output frame + FFMPEG_VIDEO_FRAME *frame=new FFMPEG_VIDEO_FRAME(); + if(Cfg::Video::Overlay){ + frame->overlay=SDL_CreateYUVOverlay( + screen->w,screen->h, + SDL_YUY2_OVERLAY, + screen); + } + else{ + frame->surface=SDL_CreateRGBSurface(0, + screen->w,screen->h,24, + 0x0000FF,0x00FF00,0xFF0000,0); + } + + // Assert conversion contexts + if(yuycontext==0 && frame->overlay){ + int fmt=frame->overlay->format; + if(fmt==SDL_YUY2_OVERLAY){ + yuycontext=sws_getContext( + stream->codec->width, + stream->codec->height, + stream->codec->pix_fmt, + frame->overlay->w, + frame->overlay->h, + PIX_FMT_YUYV422, + SWS_BILINEAR,0,0,0); + } + else{ + LogError("Unsupported video format: %d",fmt); + } + + } + if(rgbcontext==0 && frame->surface){ + int bpp=frame->surface->format->BitsPerPixel; + if(bpp==32){ + rgbcontext=sws_getContext( + stream->codec->width, + stream->codec->height, + stream->codec->pix_fmt, + frame->surface->w, + frame->surface->h, + PIX_FMT_RGB32, + SWS_BILINEAR,0,0,0); + } + else if(bpp==24){ + rgbcontext=sws_getContext( + stream->codec->width, + stream->codec->height, + stream->codec->pix_fmt, + frame->surface->w, + frame->surface->h, + PIX_FMT_RGB24, + SWS_BILINEAR,0,0,0); + } + else{ + LogError("Unsupported video bpp: %d",bpp); + } + } + + // Convert data to output format + if(yuycontext){ + SDL_LockYUVOverlay(frame->overlay); + int pitch[frame->overlay->planes]; + for(int i=0;ioverlay->planes;i++){ + pitch[i]=frame->overlay->pitches[i]; + } + sws_scale(yuycontext, + (const uint8_t* const*)dframe->data, + dframe->linesize,0,stream->codec->height, + (uint8_t* const*)frame->overlay->pixels,pitch); + SDL_UnlockYUVOverlay(frame->overlay); + } + else if(rgbcontext){ + SDL_LockSurface(frame->surface); + int pitch=frame->surface->pitch; + sws_scale(rgbcontext,dframe->data, + dframe->linesize,0,stream->codec->height, + (uint8_t* const*)&frame->surface->pixels,&pitch); + SDL_UnlockSurface(frame->surface); + } + + // Stack up frame + SDL_LockMutex(framelock); + framebuffer.Queue(frame); + SDL_UnlockMutex(framelock); + retval=true; + } + } + else{ + // Free packet + av_free_packet(packetcache); + packetcache=0; + packetsize=0; + } + } + + // Check if we need a new packet + if(FormatContext && !packetcache){ + if((packetcache=GetPacket())){ + packetsize=packetcache->size; + if(packetcache->dts==(unsigned int)AV_NOPTS_VALUE){ + if(packettime<(unsigned int)stream->start_time){ + packettime=stream->start_time; + } + packettime+=1000*packetcache->duration; + } + else{ + packettime=(packetcache->dts-stream->start_time)*1000; + } + } + } + + // Check if we need recursive reads + bool recall=(FormatContext && packetcache && !retval); + SDL_UnlockMutex(datalock); + if(recall){ + return GetFrame(); + } + else{ + return retval; + } +} + diff --git a/engines/vileVN/media/vffmpeg.h b/engines/vileVN/media/vffmpeg.h new file mode 100644 index 0000000000..d7edbd29f7 --- /dev/null +++ b/engines/vileVN/media/vffmpeg.h @@ -0,0 +1,67 @@ +/*! \class VideoFFMPEG + * \brief VideoFFMPEG implements libav/ffmpeg on top of a VideoBuffer object. + */ + +#ifndef _VFFMPEG_H_ +#define _VFFMPEG_H_ + +#include "video.h" +#include "affmpeg.h" + + +struct FFMPEG_VIDEO_FRAME { //!< Encapsulates a buffered frame + SDL_Surface *surface; //!< RGB surface + SDL_Overlay *overlay; //!< Overlay surface + int64_t pts; //!< FFMPEG timestamp + FFMPEG_VIDEO_FRAME(); + ~FFMPEG_VIDEO_FRAME(); +}; + + +class VideoFFMPEG : public VideoBuffer{ + private: + // Callbacks and utilities + static int read_callback(void *rwops,uint8_t *buf,int size); + static int write_callback(void *rwops,uint8_t *buf,int size); + static int64_t seek_callback(void *rwops,int64_t offset,int whence); + static void yuv420_to_yuyv422(FFMPEG_VIDEO_FRAME *Frame); + static void yuv_to_rgb(FFMPEG_VIDEO_FRAME *Frame); + AVPacket *GetPacket(); + bool GetFrame(); + void CloseData(); + void CloseFrames(); + +#if LIBAVCODEC_VERSION_MAJOR>=53 + AVIOContext *pb; //!< Custom IO interface +#else + ByteIOContext *pb; //!< Custom IO interface +#endif + RWops *ops; //!< Holds source data + DStack framebuffer; //!< Stacks formatted frames + SDL_mutex *datalock; //!< Mutex for controldata + SDL_mutex *framelock; //!< Mutex for framebuffer + AVFormatContext *FormatContext; //!< Holds FFMPEG data + SwsContext *yuycontext; //!< YUY2 Conversion context + SwsContext *rgbcontext; //!< RGB Conversion context + AVStream *stream; //!< Audio stream to decode + AVPacket *packetcache; //!< Intermediary packet + uint64_t packettime; //!< Time of intermediary packet + uint64_t mintime; //!< Min timestamp to decode + int packetsize; //!< Size of intermediary packet + int index; //!< Index of audio stream + AVFrame *dframe; //!< Intermediary decoding frame + SDL_Surface *screen; //!< Pointer to video surface + public: + VideoFFMPEG(); + virtual ~VideoFFMPEG(); + + // Engine interface + virtual bool Open(RWops *Resource); + virtual double Framerate(); + virtual bool Paint(); + virtual bool Decode(); + virtual void Close(); +}; + +#endif + diff --git a/engines/vileVN/media/video.cpp b/engines/vileVN/media/video.cpp new file mode 100644 index 0000000000..ab644065cb --- /dev/null +++ b/engines/vileVN/media/video.cpp @@ -0,0 +1,28 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "video.h" + +VideoBuffer::VideoBuffer(){ +} + +VideoBuffer::~VideoBuffer(){ + Close(); +} + +void VideoBuffer::Close(){ +} + + diff --git a/engines/vileVN/media/video.h b/engines/vileVN/media/video.h new file mode 100644 index 0000000000..45872c48af --- /dev/null +++ b/engines/vileVN/media/video.h @@ -0,0 +1,29 @@ +/*! \class VideoBuffer + * \brief VideoBuffer defines a generic video decoder object. + * + * VideoBuffer objects are loaded and driven by the EngineVideo class. A + * derived object is supposed to transparently provide a video feed by + * responding to the virtual methods. + */ + +#ifndef _VIDEO_H_ +#define _VIDEO_H_ + +#include "../res/rwops.h" +#include "../common/log.h" + +class VideoBuffer { + public: + VideoBuffer(); + virtual ~VideoBuffer(); + + // Engine interface + virtual bool Open(RWops *Resource)=0; + virtual double Framerate()=0; + virtual bool Paint()=0; + virtual bool Decode()=0; + virtual void Close(); +}; + +#endif + diff --git a/engines/vileVN/module.mk b/engines/vileVN/module.mk new file mode 100644 index 0000000000..c113a9bba0 --- /dev/null +++ b/engines/vileVN/module.mk @@ -0,0 +1,15 @@ +MODULE := engines/vileVN + +MODULE_OBJS := \ + detection.o \ + +MODULE_DIRS += \ + engines/vileVN + +# This module can be built as a plugin +ifeq ($(ENABLE_VILEVN), DYNAMIC_PLUGIN) +PLUGIN := 1 +endif + +# Include common rules +include $(srcdir)/rules.mk diff --git a/engines/vileVN/res/archives/abase.cpp b/engines/vileVN/res/archives/abase.cpp new file mode 100644 index 0000000000..084b4b3778 --- /dev/null +++ b/engines/vileVN/res/archives/abase.cpp @@ -0,0 +1,165 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "abase.h" + +ArchiveBase::ArchiveBase(uString Path){ + // Create top- and bottom items for the tree + items=new RedBlackTree(new ArchiveNil(),new ArchiveRoot()); + path=EDL_Realname(Path); + count=0; + + // Unset external pointer + NextPtr=0; +} + +ArchiveBase::~ArchiveBase(){ + delete items; +} + +/*! \brief Indexes an archive item + * \param Name Name of the resource to index + * \param Offset Byte offset in the archive + * \param Size Size in archive + */ +void ArchiveBase::AddItem(uString Name,int Offset,int Size){ + ArchiveItem *i=new ArchiveItem(Name,Offset,Size,Size); + items->Insert(i,SORT_STRICT); + count++; +} + +/*! \brief Indexes an archive item + * \param Name Name of the resource to index + * \param Offset Byte offset in the archive + * \param CSize Compressed image size (i.e. physical size in file) + * \param DSize Decompressed size (i.e. size of final resource) + */ +void ArchiveBase::AddItem(uString Name,int Offset,int CSize,int DSize){ + ArchiveItem *i=new ArchiveItem(Name,Offset,CSize,DSize); + items->Insert(i,SORT_STRICT); + count++; +} + +/*! \brief Retrieves a previously indexed resource item from the archive + * \param Name Name of the resource to get + * \param Offset Byte offset in the archive + * \param Size Compressed Physical size in file + */ +bool ArchiveBase::GetItem(uString Name,int &Offset,int &Size){ + bool retval=false; + ArchiveItem s(Name,0,0,0); + ArchiveItem *r=(ArchiveItem*)items->Search(&s,SORT_STRICT); + if(!r){ + r=(ArchiveItem*)items->Search(&s,SORT_NOEXT); + } + if(r){ + Offset=r->offset; + Size=r->csize; + retval=true; + } + return retval; +} + +/*! \brief Retrieves a previously indexed resource item from the archive + * \param Name Name of the resource to get + * \param Offset Byte offset in the archive + * \param CSize Compressed image size (i.e. physical size in file) + * \param DSize Decompressed size (i.e. size of final resource) + */ +bool ArchiveBase::GetItem(uString Name,int &Offset,int &CSize,int &DSize){ + bool retval=false; + ArchiveItem s(Name,0,0,0); + ArchiveItem *r=(ArchiveItem*)items->Search(&s,SORT_STRICT); + if(!r){ + r=(ArchiveItem*)items->Search(&s,SORT_NOEXT); + } + if(r){ + Offset=r->offset; + CSize=r->csize; + DSize=r->dsize; + retval=true; + } + return retval; +} + +RWops *ArchiveBase::GetResource(uString Name){ + RWops *retval=0; + int offset,size; + if(GetItem(Name,offset,size)){ + retval=new RWops(); + if(!retval->OpenFile(path.c_str(),offset,size)){ + delete retval; + retval=0; + } + } + return retval; +} + +/*! \brief Gets physical disk location of resource file + * \param Name Name of resource file + * \return Full path with directory and extension if available + * + * If resources added with AddItem have directories in their name, this will + * be parsed and remembered in the corresponding ArchiveItem so we can pull + * it out of the final blob -- Necessary for video resources and ArchiveFiles + * objects. + */ +uString ArchiveBase::GetFilename(uString Name){ + uString retval; + ArchiveItem s(Name,0,0,0); + ArchiveItem *r=(ArchiveItem*)items->Search(&s,SORT_STRICT); + if(!r){ + r=(ArchiveItem*)items->Search(&s,SORT_NOEXT); + } + if(r){ + if(r->ext.length()){ + retval=r->dir+r->base+uString(".")+r->ext; + } + else{ + retval=r->dir+r->base; + } + } + return retval; +} + +/*! \brief Enumerates all available resources + * \param Pointer to stringlist for the results + * \return Number of resources added + */ +int ArchiveBase::Enumerate(Stringlist *List){ + int retval=0; + int size=items->Count(); + if(size>0){ + RedBlackLeave *buffer[size]; + retval=items->Enumerate(buffer,size); + for(int i=0;ibase; + uString ext=((ArchiveItem*)buffer[i])->ext; + if(ext.length()){ + List->AddString(base+uString(".")+ext); + } + else if(base.length()){ + List->AddString(base); + } + } + } + return retval; +} + +int ArchiveBase::GetCount(){ + return count; +} + + diff --git a/engines/vileVN/res/archives/abase.h b/engines/vileVN/res/archives/abase.h new file mode 100644 index 0000000000..039078435e --- /dev/null +++ b/engines/vileVN/res/archives/abase.h @@ -0,0 +1,59 @@ +/*! \class ArchiveBase + * \brief Defines an archive interface + * + * There are two ways to use this class; Derived classes will index all + * available items when opening a resource as well as overriding the + * GetResource() method to assure that the underlying source properly + * populates the returning blob. + * + * Client classes will usually call the GetResource() method to get a + * given resource by name. It is the callers responebility to free the + * resource when done with it. + * + * The CSize and DSize values are for archives that uses inline compression, + * such as JAST USA Memorial Collection which has zipped bitmaps that doesnt + * really make sense until they are decompressed. + * + * NextPtr is not used internally except for setting it to NULL at start + */ +#ifndef _ABASE_H_ +#define _ABASE_H_ + +#include "aitem.h" +#include "../rwops.h" +#include "../../common/edl_fs.h" +#include "../../common/stringlist.h" +#include "../../common/dstack.h" + +#define MAX_FILENAME_LENGTH 32 + +class ArchiveBase { + private: + // Binary search tree for data + RedBlackTree *items; + int count; + protected: + // An API for caching and searching indexes + void AddItem(uString Name,int Offset,int CSize,int DSize); + bool GetItem(uString Name,int &Offset,int &CSize,int &DSize); + void AddItem(uString Name,int Offset,int Size); + bool GetItem(uString Name,int &Offset,int &Size); + + // Real path to source archive + uString path; + public: + ArchiveBase(uString Path); + virtual ~ArchiveBase(); + + // Generic Archive API + virtual RWops *GetResource(uString Name); + uString GetFilename(uString Name); + int Enumerate(Stringlist *List); + int GetCount(); + + //! Optional pointer that can be used for stacking + ArchiveBase *NextPtr; +}; + +#endif + diff --git a/engines/vileVN/res/archives/acrowdpck.cpp b/engines/vileVN/res/archives/acrowdpck.cpp new file mode 100644 index 0000000000..273dd3b22b --- /dev/null +++ b/engines/vileVN/res/archives/acrowdpck.cpp @@ -0,0 +1,110 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "acrowdpck.h" + +ArchiveCrowdPCK::ArchiveCrowdPCK(uString Path) : ArchiveBase(Path){ + FILE *rfile=fopen(EDL_Realname(Path).c_str(),"rb"); + if(rfile!=NULL){ + // Read file header + unsigned char rb[12]; + fseek(rfile,0,SEEK_SET); + if((fread(rb,1,12,rfile)>(int)0)){ + // Get record count and calculate index offsets + Uint32 rcnt=((rb[3]&0xFF)<<24)| + ((rb[2]&0xFF)<<16)| + ((rb[1]&0xFF)<<8)| + ((rb[0]&0xFF)); + unsigned int npos=4+(rcnt*12); + + // Read header size from first record + Uint32 ilen=((rb[8+3]&0xFF)<<24)| + ((rb[8+2]&0xFF)<<16)| + ((rb[8+1]&0xFF)<<8)| + ((rb[8+0]&0xFF)); + + // Get total file length + fseek(rfile,0,SEEK_END); + unsigned int tlen=ftell(rfile); + if(rcnt>0 && rcnt<0xFFFF && ilennpos){ + // Read entire index from file + fseek(rfile,0,SEEK_SET); + unsigned char *tb=new unsigned char[ilen]; + if((fread(tb,1,ilen,rfile)>(int)0)){ + // Index items + ParseIndex(tb,ilen); + } + delete [] tb; + } + + } + // Clean up + fclose(rfile); + } +} + +int ArchiveCrowdPCK::ParseIndex(unsigned char *Buffer,int Length){ + // Get record count and calculate index offsets + int returnval=0; + Uint32 rcnt=((Buffer[3]&0xFF)<<24)| + ((Buffer[2]&0xFF)<<16)| + ((Buffer[1]&0xFF)<<8)| + ((Buffer[0]&0xFF)); + unsigned int rpos=4; + unsigned int npos=4+(rcnt*12); + if(rcnt>0 && rcnt<0xFFFF){ + // Iterate records + for(unsigned int i=0;i0 && fsize>0 && fnlen>0 && fnlen(int)0)){ + if(!strncmp((char*)hbuffer,"scenario",8)){ + // XChange 2 style with header + } + else if(hbuffer[0]=='G' && hbuffer[1]=='Q'){ + // XChange 3 style without header + fseek(rfile,0,SEEK_END); + unsigned int tlength=ftell(rfile); + char *tbuffer=new char[tlength]; + fseek(rfile,0,SEEK_SET); + if(tbuffer && (fread(tbuffer,1,tlength,rfile)>(int)0)){ + Decrypt(tbuffer,tlength); + if(ParseIndex(tbuffer,tlength)){ + if(curbuffer){ + delete [] curbuffer; + } + curbuffer=tbuffer; + curlength=tlength; + } + } + } + else if(hbuffer[0]==0xDB && hbuffer[1]==0xCE){ + // Inverted Crowd Engine 1 script + fseek(rfile,0,SEEK_END); + unsigned int tlength=ftell(rfile); + char *tbuffer=new char[tlength]; + fseek(rfile,0,SEEK_SET); + if(tbuffer && (fread(tbuffer,1,tlength,rfile)>(int)0)){ + for(int i=0;i(int)0)){ + if(ParseIndex(tbuffer,tlength)){ + if(curbuffer){ + delete [] curbuffer; + } + curbuffer=tbuffer; + curlength=tlength; + } + } + } + } + + // Clean up + fclose(rfile); + } +} + +ArchiveCrowdSCE::~ArchiveCrowdSCE(){ + if(curbuffer){ + delete [] curbuffer; + } +} + +/*! \brief Decrypts the entire script collection + * \param Buffer Buffer containing the encrypted script collection + * \param Length Length of the buffer + * + * After execution, Buffer will be decrypted + */ +void ArchiveCrowdSCE::Decrypt(char *Buffer,int Length){ + // Decrypt data + char sig[]="crowd script yeah "; + int B=0,C=0,k1=0,k2=0; + for(int i=0;i0 && start+size<=Length){ + // Normal script found + AddItem(fname,start,size); + retval++; + } + else{ + LogError("Invalid SCE item at index %d",retval); + LogError("Name=(%s) offset=%d size=%d",fname,start,size); + } + } + } + return retval; +} + +/*! \brief Locates and extracts a script from a Crowd SCE file + * \param Name Name of the script + * \returns RWops with extracted resource or NULL + */ +RWops *ArchiveCrowdSCE::GetResource(uString Name){ + RWops *retval=0; + int offset,size; + if(GetItem(Name,offset,size)){ + if(size){ + // Create a new copy in ram + retval=new RWops(); + if(!retval->OpenROM(curbuffer+offset,size,false)){ + delete retval; + retval=0; + } + } + } + return retval; +} + diff --git a/engines/vileVN/res/archives/acrowdsce.h b/engines/vileVN/res/archives/acrowdsce.h new file mode 100644 index 0000000000..7ade0ec36c --- /dev/null +++ b/engines/vileVN/res/archives/acrowdsce.h @@ -0,0 +1,27 @@ +/*! \class ArchiveCrowdSCE + * \brief Handles Crowd engine 3 scenario files + * + * The SCE format is not really an archive, but an entire game in scripted + * form. This class will decrypt the entire file, keep it in RAM, and extract + * each subscript by name as it was a real archive. + */ +#ifndef _ACROWDSCE_H_ +#define _ACROWDSCE_H_ + +#include "abase.h" + +class ArchiveCrowdSCE : public ArchiveBase { + private: + char *curbuffer; //!< Holds the decrypted scripts + int curlength; //!< Length of the entire script collection + void Decrypt(char *Buffer,int Length); + int ParseIndex(char *Buffer,int Length); + public: + ArchiveCrowdSCE(uString Path); + ~ArchiveCrowdSCE(); + int Open(uString Archive); + RWops *GetResource(uString Name); +}; + +#endif + diff --git a/engines/vileVN/res/archives/acrowdsnn.cpp b/engines/vileVN/res/archives/acrowdsnn.cpp new file mode 100644 index 0000000000..dfecf5d1f6 --- /dev/null +++ b/engines/vileVN/res/archives/acrowdsnn.cpp @@ -0,0 +1,48 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "acrowdsnn.h" + +ArchiveCrowdSNN::ArchiveCrowdSNN(uString Path) : ArchiveBase(Path){ + uString listfile=path; + for(int i=listfile.length();i>0;i--){ + if(listfile[i-1]=='.'){ + listfile=listfile.substr(0,i); + listfile+="INX"; + listfile=EDL_Realname(listfile); + break; + } + if(listfile[i-1]=='/'){ + break; + } + } + FILE *rfile=fopen(listfile.c_str(),"rb"); + if(rfile!=NULL){ + unsigned char b[72]; + while(fread(b,1,72,rfile)>0){ + int size=b[0]|(b[1]<<8)|(b[2]<<16)|(b[3]<<24); + uString name=(char*)b+4; + int offset=b[68]|(b[69]<<8)|(b[70]<<16)|(b[71]<<24); + if(name.length()){ + AddItem(name,offset,size); + } + else{ + break; + } + } + fclose(rfile); + } +} + diff --git a/engines/vileVN/res/archives/acrowdsnn.h b/engines/vileVN/res/archives/acrowdsnn.h new file mode 100644 index 0000000000..5b7156dd82 --- /dev/null +++ b/engines/vileVN/res/archives/acrowdsnn.h @@ -0,0 +1,15 @@ +/*! \class ArchiveCrowdSNN + * \brief Extracts resources from Crowd SNN file cabinets + */ +#ifndef _ACROWDSNN_H_ +#define _ACROWDSNN_H_ + +#include "abase.h" + +class ArchiveCrowdSNN : public ArchiveBase { + public: + ArchiveCrowdSNN(uString Path); +}; + +#endif + diff --git a/engines/vileVN/res/archives/acwarearc2.cpp b/engines/vileVN/res/archives/acwarearc2.cpp new file mode 100644 index 0000000000..7e7d368575 --- /dev/null +++ b/engines/vileVN/res/archives/acwarearc2.cpp @@ -0,0 +1,51 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "acwarearc2.h" + +ArchiveCWareARC2::ArchiveCWareARC2(uString Path) : ArchiveBase(Path){ + FILE *rfile=fopen(EDL_Realname(Path).c_str(),"rb"); + if(rfile!=NULL){ + unsigned char b[32]; + if(fread(b,1,14,rfile)>0 && !strncmp((char*)b,"arc2",4)){ + fseek(rfile,0,SEEK_END); + unsigned int size=ftell(rfile); + unsigned int count=b[4]|(b[5]<<8)|(b[6]<<16)|(b[7]<<24); + unsigned int offset=b[8]|(b[9]<<8)|(b[10]<<16)|(b[11]<<24); + fseek(rfile,offset,SEEK_SET); + if(count>0 && count<0xFFFFFF && offset>0 && offset0 && b[0]){ + if(b[0]==0){ + break; + } + int p=b[16]|(b[17]<<8)|(b[18]<<16)|(b[19]<<24); + int l=b[20]|(b[21]<<8)|(b[22]<<16)|(b[23]<<24); + //int p3=b[24]|(b[25]<<8)|(b[26]<<16)|(b[27]<<24); + //int p4=b[28]|(b[29]<<8)|(b[30]<<16)|(b[31]<<24); + AddItem((char*)b,p,l); + } + else{ + break; + } + } + } + } + fclose(rfile); + } +} + + diff --git a/engines/vileVN/res/archives/acwarearc2.h b/engines/vileVN/res/archives/acwarearc2.h new file mode 100644 index 0000000000..dc4675e1c3 --- /dev/null +++ b/engines/vileVN/res/archives/acwarearc2.h @@ -0,0 +1,15 @@ +/*! \class ArchiveCWareARC2 + * \brief Extracts resources from CWare ARC2 file cabinets + */ +#ifndef _ACWAREARC2_H_ +#define _ACWAREARC2_H_ + +#include "abase.h" + +class ArchiveCWareARC2 : public ArchiveBase { + public: + ArchiveCWareARC2(uString Path); +}; + +#endif + diff --git a/engines/vileVN/res/archives/acwaredl1.cpp b/engines/vileVN/res/archives/acwaredl1.cpp new file mode 100644 index 0000000000..a4055369b5 --- /dev/null +++ b/engines/vileVN/res/archives/acwaredl1.cpp @@ -0,0 +1,45 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "acwaredl1.h" + +ArchiveCWareDL1::ArchiveCWareDL1(uString Path) : ArchiveBase(Path){ + FILE *rfile=fopen(EDL_Realname(Path).c_str(),"rb"); + if(rfile!=NULL){ + unsigned char h[14]; + if(fread(h,1,14,rfile)>0 && !strncmp((const char*)h,"DL1.0",5)){ + fseek(rfile,0,SEEK_END); + unsigned int size=ftell(rfile); + unsigned int count=(h[8] | h[9]<<8); + unsigned int offset=(h[10] | h[11]<<8 | h[12]<<16 | h[13]<<24); + fseek(rfile,offset,SEEK_SET); + if(count>0 && count<0xFFFF && offset>0 && offset0){ + unsigned int length=(buffer[12] | (buffer[13]<<8) | + (buffer[14]<<16) | (buffer[15]<<24)); + buffer[12]=0; + AddItem((char*)buffer,position,length); + position+=length; + } + } + } + } + fclose(rfile); + } +} + diff --git a/engines/vileVN/res/archives/acwaredl1.h b/engines/vileVN/res/archives/acwaredl1.h new file mode 100644 index 0000000000..d24d4edbac --- /dev/null +++ b/engines/vileVN/res/archives/acwaredl1.h @@ -0,0 +1,15 @@ +/*! \class ArchiveCWareDL1 + * \brief Extracts resources from CWare DL1 file cabinets + */ +#ifndef _ACWAREDL1_H_ +#define _ACWAREDL1_H_ + +#include "abase.h" + +class ArchiveCWareDL1 : public ArchiveBase { + public: + ArchiveCWareDL1(uString Path); +}; + +#endif + diff --git a/engines/vileVN/res/archives/afiles.cpp b/engines/vileVN/res/archives/afiles.cpp new file mode 100644 index 0000000000..7eb7725e29 --- /dev/null +++ b/engines/vileVN/res/archives/afiles.cpp @@ -0,0 +1,63 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "afiles.h" + + +/*! \brief Opens one or more files and pretends its an archive + * \param Pathname Path to files (Wildcard supported) + * + * This method will expand wildcarded patterns and add matching files to + * the archive. All pathnames are case insensitive to make autodetection + * on unix systems feasable. + * + * Please note that there is no defined behaviour for handling directories, + * only files are supported input. + */ +ArchiveFiles::ArchiveFiles(uString Path) : ArchiveBase(Path){ + Stringlist list=EDL_Expandname(Path); + int items=list.GetCount(); + for(int i=0;i0){ + AddItem(pathname,0,size); + } + } + } +} + +RWops *ArchiveFiles::GetResource(uString Name){ + RWops *retval=0; + int offset,size; + if(GetItem(Name,offset,size)){ + // Parse real path + uString path=EDL_Realname(GetFilename(Name)); + + // Open file as a blob + retval=new RWops(); + if(!retval->OpenFile(path.c_str(),"rb")){ + delete retval; + retval=0; + } + } + return retval; +} + + diff --git a/engines/vileVN/res/archives/afiles.h b/engines/vileVN/res/archives/afiles.h new file mode 100644 index 0000000000..f257fc1d26 --- /dev/null +++ b/engines/vileVN/res/archives/afiles.h @@ -0,0 +1,16 @@ +/*! \class ArchiveFiles + * \brief Treats a collection of files as an archive + */ +#ifndef _AFILES_H_ +#define _AFILES_H_ + +#include "abase.h" + +class ArchiveFiles : public ArchiveBase { + public: + ArchiveFiles(uString Path); + RWops *GetResource(uString Name); +}; + +#endif + diff --git a/engines/vileVN/res/archives/aikura.cpp b/engines/vileVN/res/archives/aikura.cpp new file mode 100644 index 0000000000..5ff8be492a --- /dev/null +++ b/engines/vileVN/res/archives/aikura.cpp @@ -0,0 +1,104 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "aikura.h" + +ArchiveIkura::ArchiveIkura(uString Path) : ArchiveBase(Path){ + FILE *rfile=fopen(EDL_Realname(Path).c_str(),"rb"); + if(rfile!=NULL){ + unsigned char hdr[32]; + if(fread(hdr,1,32,rfile)>0){ + if(!strncmp((char*)hdr,"SM2MPX10",8)){ + // Moder kind of cabinet with a header! + int dlen=hdr[12]|(hdr[13]<<8)|(hdr[14]<<16)|(hdr[15]<<24); + int dstart=hdr[28]|(hdr[29]<<8)|(hdr[30]<<16)|(hdr[31]<<24); + fseek(rfile,0,SEEK_SET); + unsigned char *dbuf=new unsigned char[dlen]; + if(fread(dbuf,1,dlen,rfile)>0){ + for(int i=dstart;i1 && td2>td1 && ti1>0 && ti2>ti1){ + // Go ahead with decoding + int dlen=ti1; + int dstart=2; + fseek(rfile,0,SEEK_END); + int fullsize=ftell(rfile); + fseek(rfile,0,SEEK_SET); + unsigned char *dbuf=new unsigned char[dlen]; + if(fread(dbuf,1,dlen,rfile)>0){ + // Get consequtive entries + for(int i=dstart;i+16start){ + AddItem(tbuf,start,end-start); + } + else{ + AddItem(tbuf,start,fullsize); + break; + } + } + } + delete [] dbuf; + } + } + } + fclose(rfile); + } +} + diff --git a/engines/vileVN/res/archives/aikura.h b/engines/vileVN/res/archives/aikura.h new file mode 100644 index 0000000000..10fe57171a --- /dev/null +++ b/engines/vileVN/res/archives/aikura.h @@ -0,0 +1,15 @@ +/*! \class ArchiveIkura + * \brief Extracts resources from IkuraGDL file cabinets + */ +#ifndef _AIKURA_H_ +#define _AIKURA_H_ + +#include "abase.h" + +class ArchiveIkura : public ArchiveBase { + public: + ArchiveIkura(uString Path); +}; + +#endif + diff --git a/engines/vileVN/res/archives/aitem.cpp b/engines/vileVN/res/archives/aitem.cpp new file mode 100644 index 0000000000..aa921654f9 --- /dev/null +++ b/engines/vileVN/res/archives/aitem.cpp @@ -0,0 +1,95 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "aitem.h" + +/*! \brief Creates an compressed item and parses the content + * \param Path Path to resource + * \param Offset Offset in archive + * \param CSize Compressed size in archive + * \param DSize Decompressed size + */ +ArchiveItem::ArchiveItem(uString Path,int Offset,int CSize,int DSize){ + Set(Path,Offset,CSize,DSize); +} + +ArchiveItem::ArchiveItem(){ + offset=0; + csize=0; + dsize=0; +} + +ArchiveNil::ArchiveNil() : ArchiveItem() { +} + +ArchiveRoot::ArchiveRoot() : ArchiveItem() { + int rootsize=128; + char rootbuffer[rootsize+1]; + memset(rootbuffer,'}',rootsize); + rootbuffer[rootsize]=0; + base=rootbuffer; + ext=base; +} + +/*! \brief Creates an compressed item and parses the content + * \param Path Path to resource + * \param Offset Offset in archive + * \param CSize Compressed size in archive + * \param DSize Decompressed size + */ +void ArchiveItem::Set(uString Path,int Offset,int CSize,int DSize){ + // Parse and convert name to lower case + int basestart=0; + int baseend=0; + Path=EDL_Lower(Path); + for(int i=Path.length();i>0;i--){ + if(Path[i-1]=='.'){ + baseend=i-1; + } + else if(Path[i-1]=='/' || Path[i-1]=='\\'){ + basestart=i; + break; + } + } + + // Set values + offset=Offset; + csize=CSize; + dsize=DSize; + dir=Path.substr(0,basestart); + if(baseend){ + base=Path.substr(basestart,baseend-basestart); + ext=Path.substr(baseend+1); + } + else{ + base=Path.substr(basestart); + ext=""; + } +} + + +/*! \brief Compares two string items + * \param Leave Object to compare with + * \param Mode With or without extension + * \return NULL with match + */ +int ArchiveItem::Compare(RedBlackLeave *Leave,int Mode){ + int retval=base.compare(((ArchiveItem*)Leave)->base); + if(!retval && Mode==SORT_STRICT){ + retval=ext.compare(((ArchiveItem*)Leave)->ext); + } + return retval; +} + diff --git a/engines/vileVN/res/archives/aitem.h b/engines/vileVN/res/archives/aitem.h new file mode 100644 index 0000000000..3c379bacf5 --- /dev/null +++ b/engines/vileVN/res/archives/aitem.h @@ -0,0 +1,54 @@ +/*! \class ArchiveItem + * \brief Red-black leave for an archive item + * + * See RedBlack classes for further details on sorting/stacking, and refer to + * the ArchiveBase class for the management. + */ +#ifndef _ARCHIVEITEM_H_ +#define _ARCHIVEITEM_H_ + +#include "../../common/edl_common.h" +#include "../../common/redblack.h" +#include "../../common/log.h" + +#define SORT_STRICT 1 +#define SORT_NOEXT 2 + +class ArchiveItem : public RedBlackLeave { + private: + virtual int Compare(RedBlackLeave *Leave,int Mode); + public: + // Constructors + ArchiveItem(uString Path,int Offset,int CSize,int DSize); + ArchiveItem(); + + // Helper for configuring existing items + void Set(uString Path,int Offset,int CSize,int DSize); + + // Object data + uString dir; //!< Directory (if resource is a file) + uString base; //!< Resource filename (without extension) + uString ext; //!< Resource extension (if any) + int offset; //!< Resource offset in archive + int csize; //!< Size of compressed resource + int dsize; //!< Size of decompressed resource +}; + +/*! \class ArchiveRoot + * \brief Convenience class for instancing a root red/black object + */ +class ArchiveRoot : public ArchiveItem { + public: + ArchiveRoot(); +}; + +/*! \class ArchiveNil + * \brief Convenience class for instancing a nil red/black object + */ +class ArchiveNil : public ArchiveItem { + public: + ArchiveNil(); +}; + +#endif + diff --git a/engines/vileVN/res/archives/ajast.cpp b/engines/vileVN/res/archives/ajast.cpp new file mode 100644 index 0000000000..46831c8e9a --- /dev/null +++ b/engines/vileVN/res/archives/ajast.cpp @@ -0,0 +1,92 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "ajast.h" + +ArchiveJAST::ArchiveJAST(uString Path) : ArchiveBase(Path){ + FILE *rfile=fopen(path.c_str(),"rb"); + if(rfile!=NULL){ + unsigned char h[10]; + if(fread(h,1,10,rfile)>0){ + uString name; + fseek(rfile,0,SEEK_END); + unsigned int size=ftell(rfile); + unsigned int offset=(h[6] | h[7]<<8 | h[8]<<16 | h[9]<<24)-1; + if(size>offset && !strncmp((char*)h,"VFTech",6)){ + fseek(rfile,offset,SEEK_SET); + unsigned char b[(size-offset)+1]; + size=fread(b,1,size-offset,rfile); + for(unsigned int i=0;i+8(int)0){ + // Decompress with zlib + dsize=cbuffer[0]|(cbuffer[1]<<8)| + (cbuffer[2]<<16)|(cbuffer[3]<<24); + unsigned char *dbuffer=new unsigned char[dsize]; + uLongf lcsize=csize-4; + uLongf ldsize=dsize; + uncompress(dbuffer,&ldsize,cbuffer+4,lcsize); + + // Create blob with input data + retval=new RWops(); + if(!retval->OpenROM((char*)dbuffer,dsize,true)){ + delete [] dbuffer; + delete retval; + retval=0; + } + } + delete [] cbuffer; + fclose(rf); + } + } + return retval; +} + diff --git a/engines/vileVN/res/archives/ajast.h b/engines/vileVN/res/archives/ajast.h new file mode 100644 index 0000000000..af103f076d --- /dev/null +++ b/engines/vileVN/res/archives/ajast.h @@ -0,0 +1,17 @@ +/*! \class ArchiveJAST + * \brief Extracts resources from JAST USA Memorial Collection file cabinets + */ +#ifndef _AJAST_H_ +#define _AJAST_H_ + +#include +#include "abase.h" + +class ArchiveJAST : public ArchiveBase { + public: + ArchiveJAST(uString Path); + RWops *GetResource(uString Name); +}; + +#endif + diff --git a/engines/vileVN/res/archives/as21.cpp b/engines/vileVN/res/archives/as21.cpp new file mode 100644 index 0000000000..a1694e6cab --- /dev/null +++ b/engines/vileVN/res/archives/as21.cpp @@ -0,0 +1,38 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "as21.h" + +ArchiveS21::ArchiveS21(uString Path) : ArchiveBase(Path){ + FILE *rfile=fopen(path.c_str(),"rb"); + if(rfile!=NULL){ + unsigned char b[255]; + if(fread(b,1,12,rfile)>0){ + if(b[0]==0x89 && b[1]==0xF5 && b[2]==0x8A && b[3]==0x79){ + int ilength=((b[7]<<24)|(b[6]<<16)|(b[5]<<8)|b[4])-4; + int iread=12; + int offset=ilength+4; + while(ilength>iread && fread(b,1,24,rfile)>22){ + int dlength=(b[23]<<24)|(b[22]<<16)|(b[21]<<8)|b[20]; + AddItem((char*)b,offset,dlength); + offset+=dlength; + iread+=24; + } + } + } + fclose(rfile); + } +} + diff --git a/engines/vileVN/res/archives/as21.h b/engines/vileVN/res/archives/as21.h new file mode 100644 index 0000000000..459356d06b --- /dev/null +++ b/engines/vileVN/res/archives/as21.h @@ -0,0 +1,15 @@ +/*! \class ArchiveS21 + * \brief Extracts resources from S21 file cabinets + */ +#ifndef _AS21_H_ +#define _AS21_H_ + +#include "abase.h" + +class ArchiveS21 : public ArchiveBase { + public: + ArchiveS21(uString Path); +}; + +#endif + diff --git a/engines/vileVN/res/archives/atlove.cpp b/engines/vileVN/res/archives/atlove.cpp new file mode 100644 index 0000000000..2937362c25 --- /dev/null +++ b/engines/vileVN/res/archives/atlove.cpp @@ -0,0 +1,96 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "atlove.h" + +#define GETBYTE(B) ((B)[0]) +#define GETWORD(B) ((B)[0]|((B)[1]<<8)) +#define GETDWORD(B) ((B)[0]|((B)[1]<<8)|((B)[2]<<16)|((B)[3]<<24)) + +ArchiveTLove::ArchiveTLove(uString Path) : ArchiveBase(Path){ + FILE *rfile=fopen(path.c_str(),"rb"); + if(rfile!=NULL){ + fseek(rfile,0,SEEK_END); + unsigned int size=ftell(rfile); + unsigned char b[16]; + fseek(rfile,0,SEEK_SET); + if(size>16 && fread(b,1,2,rfile)==2){ + Uint32 loffset=0; + Uint16 slice=GETWORD(b); + if(sliceloffset; + if(test5 && test6){ + loffset=offset; + test++; + } + else{ + test=0; + break; + } + } + + // Index files if valid + loffset=0; + if(test>10 && fread(b,1,16,rfile)==16){ + for(int i=0;i0){ + if(!strncmp((char*)hdr,"ViLEPACK",8)){ + // Moder kind of cabinet with a header! + int dlen=hdr[12]|(hdr[13]<<8)|(hdr[14]<<16)|(hdr[15]<<24); + fseek(rfile,0,SEEK_SET); + unsigned char *dbuf=new unsigned char[dlen]; + if(fread(dbuf,1,dlen,rfile)>0){ + for(int i=16;i0){ + // Do a verification run to compensate for missing magic header + unsigned int types=b[0]|(b[1]<<8)|(b[2]<<16)|(b[3]<<24); + unsigned int offset=0; + bool ok=(types>0); + for(unsigned int i=0;ok && ioffset; + ok&=start0;i--){ + if(listfile[i-1]=='.'){ + listfile=listfile.substr(0,i); + listfile+="LST"; + listfile=EDL_Realname(listfile); + break; + } + if(listfile[i-1]=='/'){ + break; + } + } + FILE *rfile=fopen(listfile.c_str(),"rb"); + if(rfile!=NULL){ + unsigned char b[16]; + if(fread(b,1,16,rfile)>0){ + if(!strncmp((char*)b,"D_Lib -02-",10)){ + uString name; + unsigned int offset=0; + unsigned int size=0; + int isize=0; + while(fread(b,1,16,rfile)>14){ + // Use this items offset to calculate previous size + unsigned int newoffset=b[12]|b[13]<<8|b[14]<<16|b[15]<<24; + isize=newoffset-offset; + if(isize<0){ + size=isize*-1; + } + else{ + size=isize; + } + if(size>0){ + // Add previous item (Last one is a dummy) + AddItem(name,offset,size); + } + + // Prepare for next item (Last one is a dummy) + offset=newoffset; + name=(char*)b; + } + } + } + fclose(rfile); + } +} + diff --git a/engines/vileVN/res/archives/awindy.h b/engines/vileVN/res/archives/awindy.h new file mode 100644 index 0000000000..393f8d52c8 --- /dev/null +++ b/engines/vileVN/res/archives/awindy.h @@ -0,0 +1,15 @@ +/*! \class ArchiveWindy + * \brief Extracts resources from Windy file cabinets + */ +#ifndef _AWINDY_H_ +#define _AWINDY_H_ + +#include "abase.h" + +class ArchiveWindy : public ArchiveBase { + public: + ArchiveWindy(uString Path); +}; + +#endif + diff --git a/engines/vileVN/res/cache.cpp b/engines/vileVN/res/cache.cpp new file mode 100644 index 0000000000..8b455f8910 --- /dev/null +++ b/engines/vileVN/res/cache.cpp @@ -0,0 +1,97 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "cache.h" + +Cache::Cache(int Size){ + root.Surface=0; + root.NextPtr=0; + maxsize=Size; + size=0; +} + +Cache::~Cache(){ + while(root.NextPtr){ + CacheItem *tmp=root.NextPtr->NextPtr; + SDL_FreeSurface(root.NextPtr->Surface); + delete root.NextPtr; + root.NextPtr=tmp; + } +} + +/*! \brief Retrieves resource from storage + * \param Name Name of the resource + * \return Pointer to resource or NULL + */ +SDL_Surface *Cache::GetSurface(uString Name){ + SDL_Surface *retval=0; + CacheItem *tmpptr=&root; + while(tmpptr->NextPtr && tmpptr->NextPtr->Name!=Name){ + tmpptr=tmpptr->NextPtr; + } + if(tmpptr->NextPtr){ + CacheItem *item=tmpptr->NextPtr; + retval=item->Surface; + tmpptr->NextPtr=tmpptr->NextPtr->NextPtr; + item->NextPtr=root.NextPtr; + root.NextPtr=item; + } + return retval; +} + +/*! \brief Stores a resource pointer on the stack + * \param Name Name of the resource + * \param Surface Pointer to store + */ +void Cache::SetSurface(uString Name,SDL_Surface *Surface){ + CacheItem *tmpptr=&root; + while(tmpptr->NextPtr && tmpptr->NextPtr->Name!=Name){ + tmpptr=tmpptr->NextPtr; + } + if(tmpptr->NextPtr){ + // Update existing item + CacheItem *item=tmpptr->NextPtr; + if(item->Surface!=Surface){ + SDL_FreeSurface(item->Surface); + item->Surface=Surface; + } + tmpptr->NextPtr=tmpptr->NextPtr->NextPtr; + item->NextPtr=root.NextPtr; + root.NextPtr=item; + } + else{ + // Add new item + CacheItem *item=new CacheItem; + item->Name=Name; + item->Surface=Surface; + item->NextPtr=root.NextPtr; + root.NextPtr=item; + size++; + } + + if(size>maxsize){ + // Purge queue + tmpptr=&root; + while(tmpptr->NextPtr->NextPtr){ + tmpptr=tmpptr->NextPtr; + } + CacheItem *item=tmpptr->NextPtr; + tmpptr->NextPtr=0; + SDL_FreeSurface(item->Surface); + delete item; + } +} + + diff --git a/engines/vileVN/res/cache.h b/engines/vileVN/res/cache.h new file mode 100644 index 0000000000..9fee6206f1 --- /dev/null +++ b/engines/vileVN/res/cache.h @@ -0,0 +1,40 @@ +/*! \class Cache + * \brief Basic class for caching processed graphics + * + * This is a highly experimental realtime cacher designed to optimize ViLE + * per-engine. We have tested a couple of conventional oft-used-resource + * caches directly in the Resource manager, but these has failed to produce + * significant effects as so many of the processing steps are performed + * after decoding the base graphic format (Color keying, masking, etc). + * + * The Cache class cannot be used transparantly so it is not recomended to + * implement it until an engine is matured and/or fully understood. Check + * the Crowd engine for sample implementation. + */ +#ifndef _CACHE_H_ +#define _CACHE_H_ + +#include "../common/edl_gfx.h" +#include "rwops.h" + +// Cache item +struct CacheItem { + SDL_Surface *Surface; + uString Name; + CacheItem *NextPtr; +}; + +class Cache { + private: + CacheItem root; + int maxsize; + int size; + public: + Cache(int Size); + ~Cache(); + void SetSurface(uString Name,SDL_Surface *Surface); + SDL_Surface *GetSurface(uString Name); +}; + +#endif + diff --git a/engines/vileVN/res/converters/ccrowd.cpp b/engines/vileVN/res/converters/ccrowd.cpp new file mode 100644 index 0000000000..50f61a3264 --- /dev/null +++ b/engines/vileVN/res/converters/ccrowd.cpp @@ -0,0 +1,201 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "ccrowd.h" + +/*! \brief Demangles and converts a CWP (Crowd games) + * \param Object Input data + * \returns Converted imagedata or NULL if failed + */ +SDL_Surface *CCrowd::cwp(RWops *Object){ + // Copy source data to memory + SDL_Surface *retval=0; + int srclen=Object->Seek(0,SEEK_END); + char *dstbuf=new char[srclen+31]; + char *srcbuf=new char[srclen]; + Object->Seek(0,SEEK_SET); + Object->Read(srcbuf,srclen); + + // Reconstruct png header + int i=0; + dstbuf[i++]=137; + dstbuf[i++]='P'; + dstbuf[i++]='N'; + dstbuf[i++]='G'; + dstbuf[i++]=13; + dstbuf[i++]=10; + dstbuf[i++]=26; + dstbuf[i++]=10; + dstbuf[i++]=0; + dstbuf[i++]=0; + dstbuf[i++]=0; + dstbuf[i++]=13; + dstbuf[i++]='I'; + dstbuf[i++]='H'; + dstbuf[i++]='D'; + dstbuf[i++]='R'; + for(int j=4;j<25;j++){ + dstbuf[i++]=srcbuf[j]; + } + dstbuf[i++]='I'; + dstbuf[i++]='D'; + dstbuf[i++]='A'; + dstbuf[i++]='T'; + for(int j=25;jformat->Rshift; + retval->format->Rshift=retval->format->Bshift; + retval->format->Bshift=tmp; + tmp=retval->format->Rmask; + retval->format->Rmask=retval->format->Bmask; + retval->format->Bmask=tmp; + EDL_SetAlpha(retval,0,255); + } + + // Clean up buffers + SDL_FreeRW(dest); + delete [] srcbuf; + delete [] dstbuf; + + return retval; +} + +SDL_Surface *CCrowd::zbm(RWops *Object){ + SDL_Surface *retval=0; + if(Object){ + // Poke the header + Uint8 magic[8]; + Uint8 rlen[8]; + Uint8 ctype; + Uint8 lastchar; + Object->Seek(0,SEEK_SET); + Object->Read(magic,8); + Object->Read(&ctype,1); + Object->Read(&lastchar,1); + Object->Read(&rlen,4); + + // Verify basic header data and ctype type + if(magic[0]=='S' && magic[1]=='Z' && + magic[2]=='D' && magic[3]=='D' && + magic[4]==0x88 && magic[5]==0xF0 && + magic[6]==0x27 && magic[7]==0x33 && + ctype=='A'){ + // Convert values + Uint32 reallength=rlen[3]<<24|rlen[2]<<16|rlen[1]<<8|rlen[0]; + Uint32 stringlen=0; + Uint32 stringpos=0; + + // Prepp target + Uint8 *tbuffer=new Uint8[reallength]; + Uint32 tindex=0; + + // Prepare table + Uint8 table[0x1000]={0x20}; + Uint32 curtabent=0xFF0; + Uint16 bytetype=0; + + // Decompress using microsofts SZDD algorithm (content is xored) + while(tindexRead(&b,1)){ + break; + } + bytetype=b|0xFF00; + } + if(bytetype&1){ + if (1!=Object->Read(&b,1)){ + break; + } + } + else{ + Uint8 b1,b2; + if (1!=Object->Read(&b1,1)) break; + if (1!=Object->Read(&b2,1)) break; + + /* Format: + * b1 b2 + * AB CD + * where CAB is the stringoffset in the table + * and D+3 is the len of the string + */ + stringpos=b1|((b2&0xf0)<<4); + stringlen=(b2&0xf)+2; + + /* 3, but we use a byte already below ... */ + b=table[stringpos]; + stringpos=(stringpos+1)&0xFFF; + } + bytetype>>=1; + } + + /* store b in table */ + table[curtabent++]=b; + curtabent&=0xFFF; + tbuffer[tindex++]=b; + } + + // Verify bitmap content and decrypt it + if(tbuffer[0]^0xFF=='B' && tbuffer[1]^0xFF=='M'){ + for(int i=0;i<100;i++){ + tbuffer[i]^=0xFF; + } +/* +FILE *f=fopen("zbmdump.bmp","wb"); +fwrite(tbuffer,tindex,1,f); +fclose(f); +exit(0); +*/ + + + SDL_RWops *dest=SDL_RWFromMem(tbuffer,tindex); + SDL_RWseek(dest,0,SEEK_SET); + SDL_Surface *tmp=SDL_LoadBMP_RW(dest,1); + if(tmp){ + // Convert to native depth + retval=EDL_CreateSurface(tmp->w,tmp->h); + EDL_BlitSurface(tmp,0,retval,0); + SDL_FreeSurface(tmp); + } + } + } + } + return retval; +} + diff --git a/engines/vileVN/res/converters/ccrowd.h b/engines/vileVN/res/converters/ccrowd.h new file mode 100644 index 0000000000..4284f36807 --- /dev/null +++ b/engines/vileVN/res/converters/ccrowd.h @@ -0,0 +1,16 @@ +/*! \class CCrowd + * \brief Conversion routines for Crowd Engine + */ +#ifndef _CCROWD_H_ +#define _CCROWD_H_ + +#include "../rwops.h" +#include "../../common/edl_gfx.h" + +class CCrowd { + public: + static SDL_Surface *cwp(RWops *Object); + static SDL_Surface *zbm(RWops *Object); +}; + +#endif diff --git a/engines/vileVN/res/converters/ccware.cpp b/engines/vileVN/res/converters/ccware.cpp new file mode 100644 index 0000000000..f52415507a --- /dev/null +++ b/engines/vileVN/res/converters/ccware.cpp @@ -0,0 +1,76 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "ccware.h" + +SDL_Surface *CCWare::lz_32b(RWops *Object){ + SDL_Surface *retval=0; + if(Object){ + Uint8 header[10]={0}; + Object->Seek(0,SEEK_SET); + Object->Read(header,10); + unsigned int csize=header[5]<<24|header[4]<<16|header[3]<<8|header[2]; + unsigned int usize=header[9]<<24|header[8]<<16|header[7]<<8|header[6]; + if(header[0]=='L' && header[1]=='Z'){ + // Prepp input/output + Uint8 outbuffer[usize]; + Uint8 inbuffer[csize]; + Object->Read(inbuffer,csize); + + // Create ringbuffer + Uint32 bufsize=0x1000; // Ringbuffer size. + Uint8 buffer[bufsize]; + Uint32 mask=bufsize-1; + Uint32 rin=0xFEE; + for(unsigned int i=0;i>=1){ + if(in>4)&0xF00); + Uint16 count=((data>>8)&0xF)+3; + while(count--){ + outbuffer[out++]=buffer[rin]=buffer[rout]; + rin=(rin+1)&mask; + rout=(rout+1)&mask; + } + } + else{ + // Not compressed + buffer[rin]=outbuffer[out++]=inbuffer[in++]; + rin=(rin+1)&mask; + } + } + } + } + SDL_RWops *src=SDL_RWFromMem(outbuffer,usize); + SDL_Surface *tmp=SDL_LoadBMP_RW(src,true); + retval=EDL_CreateSurface(tmp->w,tmp->w); + SDL_BlitSurface(tmp,0,retval,0); + SDL_FreeSurface(tmp); + } + } + return retval; +} + diff --git a/engines/vileVN/res/converters/ccware.h b/engines/vileVN/res/converters/ccware.h new file mode 100644 index 0000000000..35131e5ee5 --- /dev/null +++ b/engines/vileVN/res/converters/ccware.h @@ -0,0 +1,17 @@ +/*! \class CCWare + * \brief Conversion routines for Windy Engine + * + * Actually converts bitmaps for the s21 engine used by the Mayclub remake + */ +#ifndef _CCWARE_H_ +#define _CCWARE_H_ + +#include "../rwops.h" +#include "../../common/edl_gfx.h" + +class CCWare { + public: + static SDL_Surface *lz_32b(RWops *Object); +}; + +#endif diff --git a/engines/vileVN/res/converters/cikura.cpp b/engines/vileVN/res/converters/cikura.cpp new file mode 100644 index 0000000000..f3a265ea06 --- /dev/null +++ b/engines/vileVN/res/converters/cikura.cpp @@ -0,0 +1,768 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "cikura.h" + +/*! \brief Decompresses and converts an 24bit GAN animation (Ikura games) + * \param Object Input data + * \returns Array of converted imagedata or NULL if failed + * + * The last element in the array will be NULL, denoting the end of the + * animation cycle. + */ +SDL_Surface **CIkura::gan(RWops *Object){ + // Get number of frames + SDL_Surface **retval=0; + unsigned char hdr[16]; + Object->Seek(12,SEEK_SET); + Object->Read(hdr,4); + int framecount=hdr[0]|(hdr[1]<<8)|(hdr[2]<<16)|(hdr[3]<<24); + int width=640; + int height=480; + if(framecount){ + retval=new SDL_Surface*[framecount+1]; + retval[framecount]=0; + } + else{ + retval=0; + } + + // Iterate frames + unsigned char *lstbuf=0; + for(int frame=0;frameSeek(0x2010+(frame*16),SEEK_SET); + Object->Read(hdr,16); + int ref=hdr[4]|(hdr[5]<<8)|(hdr[6]<<16)|(hdr[7]<<24); + int offset=hdr[8]|(hdr[9]<<8)|(hdr[10]<<16)|(hdr[11]<<24); + int srclen=hdr[12]|(hdr[13]<<8)|(hdr[14]<<16)|(hdr[15]<<24); + int dstlen=width*height*3; + unsigned char *srcbuf=new unsigned char[srclen*2]; + unsigned char *dstbuf=new unsigned char[dstlen*2]; + Object->Seek(offset,SEEK_SET); + Object->Read(srcbuf,srclen); + + // Decompress frame data + int ipos=0; + int opos=0; + Uint32 last=0xFFFFFFFF; + Uint32 color=0; + Uint32 cnt=0; + Uint32 length=0; + if(ref){ + // Extract semitransparent image (Fill with previous frame) + int hdrlen=srcbuf[0]|(srcbuf[1]<<8)| + (srcbuf[2]<<16)|(srcbuf[3]<<24); + int hpos=4; + ipos=hdrlen; + while(ipos2){ + cnt-=2; + } + else{ + cnt=0; + } + } + last=color; + } + else{ + cnt--; + dstbuf[opos++]=last&0xFF; + dstbuf[opos++]=(last>>8)&0xFF; + dstbuf[opos++]=(last>>16)&0xFF; + } + } + length=srcbuf[hpos++]; + if(length&0x80){ + length&=0x7F; + length<<=8; + length+=srcbuf[hpos++]; + if(length==0x7FFF){ + length=srcbuf[hpos+0]|(srcbuf[hpos+1]<<8)| + (srcbuf[hpos+2]<<16)|(srcbuf[hpos+3]<<24); + hpos+=4; + } + } + while(lstbuf && length--){ + // Copy data from previous buffer + int tpos=opos; + dstbuf[tpos++]=lstbuf[opos++]; + dstbuf[tpos++]=lstbuf[opos++]; + dstbuf[tpos++]=lstbuf[opos++]; + } + } + } + else{ + // Extract solid frame + while(ipos2){ + cnt=cnt-2; + while(cnt--){ + dstbuf[opos+0]=dstbuf[opos-3]; + dstbuf[opos+1]=dstbuf[opos-2]; + dstbuf[opos+2]=dstbuf[opos-1]; + opos+=3; + } + } + } + last=color; + } + } + + // Convert result to a 24bit surface + retval[frame]=SDL_CreateRGBSurface(SDL_SWSURFACE,width,height,24, +#if SDL_BYTEORDER == SDL_BIG_ENDIAN + 0xff000000,0x00ff0000,0x0000ff00,0x00000000); +#else + 0x000000ff,0x0000ff00,0x00ff0000,0x00000000); +#endif + opos=0; + for (int y=0;y + (retval[frame]->pixels)+ + (y*retval[frame]->pitch)+ + (x*retval[frame]->format->BytesPerPixel); + pixels[2]=dstbuf[opos++]; + pixels[1]=dstbuf[opos++]; + pixels[0]=dstbuf[opos++]; + } + } + + // Clean up buffers + if(lstbuf){ + delete [] lstbuf; + } + lstbuf=dstbuf; + delete [] srcbuf; + } + if(lstbuf){ + delete [] lstbuf; + } + return retval; +} + + +/*! \brief Decompresses and converts an 8bit GGD (Ikura games) + * \param Object Input data + * \returns Converted imagedata or NULL if failed + * + * These images are used as hitmaps in newer ikura games as well as all + * opaque graphics found in the nocturnal illusion remake. + */ +SDL_Surface *CIkura::ggd_8b(RWops *Object){ + // Extract graphic attributes + SDL_Surface *retval=0; + unsigned char hdr[16]; + Object->Seek(0,SEEK_SET); + Object->Read(hdr,16); + int depth=8; + int width=hdr[8]|(hdr[9]<<8)|(hdr[10]<<16)|(hdr[11]<<24); + int height=hdr[12]|(hdr[13]<<8)|(hdr[14]<<16)|(hdr[15]<<24); + if(height<0){ + height=height*-1; + } + if(depth>0 && width>0 && height>0){ + // Copy source data to memory + int srclen=Object->Seek(0,SEEK_END); + int dstlen=(width+1)*(height+1); + unsigned char *dstbuf=new unsigned char[dstlen]; + unsigned char *srcbuf=new unsigned char[srclen]; + Object->Seek(0,SEEK_SET); + Object->Read(srcbuf,srclen); + + // Set input to 16b header+28b unknown + int ipos=16+28; + int opos=0; + + // Extract palette + Uint32 palette[256]; + for(int i=0;i<256;i++){ + palette[i]= + (srcbuf[ipos+(i*4)+0])| + (srcbuf[ipos+(i*4)+1]<<8)| + (srcbuf[ipos+(i*4)+2]<<16)| + (srcbuf[ipos+(i*4)+3]<<24); + } + + // Decompress imagedata + ipos+=256*4; + ipos+=4; + + int p=0; + while(ipos=srclen){ + // Pragmatic hack to fix valgrind detected error + break; + } + else if(ctrl&1){ + dstbuf[opos++]=srcbuf[ipos++]; + p++; + } + else{ + Uint32 backword=srcbuf[ipos]; + backword|=(srcbuf[ipos+1]&0xF0)<<4; + backword=(p-backword-19)&0x0FFF; + backword++; + int leng=(srcbuf[ipos+1]&0x0F)+3; + ipos+=2; + int zero=backword-p; + p+=leng; + if(zero>0){ + if(leng>=1; + } + } + + + // Convert result to a 24bit surface + retval=EDL_CreateSurface(width,height); + opos=0; + for (int y=0;y(retval->pixels)+ + (y*retval->pitch)+(x*retval->format->BytesPerPixel); + Uint8 pixel=dstbuf[opos++]; + Uint8 r=palette[pixel]&0xFF; + Uint8 g=(palette[pixel]>>8)&0xFF; + Uint8 b=(palette[pixel]>>16)&0xFF; + //Uint8 a=(palette[pixel]>>24)&0xFF; + pixels[0]=b; + pixels[1]=g; + pixels[2]=r; + pixels[3]=0xFF; + } + } + + // Clean up buffers + delete [] srcbuf; + delete [] dstbuf; + } + else{ + LogError("Invalid GGD Header"); + } + return retval; +} + +/*! \brief Decrypts 32bit GGP (Ikura games) and load PNG image data + * \param Object Input data + * \returns Converted imagedata or NULL if failed + * + * This code is based upon AnimED by WinKillerStudio (http://wks.arai-kibou.ru/) + */ + +SDL_Surface *CIkura::ggp_32b(RWops *Object){ + SDL_Surface *retval=0; + unsigned char hdr[36]; + Object->Seek(0,SEEK_SET); + Object->Read(hdr,36); + //Uint32 bitdepth=hdr[8]|(hdr[9]<<8)|(hdr[10]<<16)|(hdr[11]<<24); + //Uint32 offset=hdr[20]|(hdr[21]<<8)|(hdr[22]<<16)|(hdr[23]<<24); + Uint32 length=hdr[24]|(hdr[25]<<8)|(hdr[26]<<16)|(hdr[27]<<24); + //Uint32 regoffset=hdr[28]|(hdr[29]<<8)|(hdr[30]<<16)|(hdr[31]<<24); + Uint32 reglength=hdr[32]|(hdr[33]<<8)|(hdr[34]<<16)|(hdr[35]<<24); + if(!strncmp("GGPFAIKE",(char*)hdr,8) && length>0){ + // Decrypt imagedata + unsigned char buffer[length]; + Object->Seek(36+reglength,SEEK_SET); + Object->Read(buffer,length); + for(unsigned int i=0;iSeek(0,SEEK_SET); + Object->Read(hdr,24); + Uint16 width=hdr[8]|hdr[9]<<8; + Uint16 height=hdr[10]|hdr[11]<<8; + //Uint32 field_c=hdr[12]|(hdr[13]<<8)|(hdr[14]<<16)|(hdr[15]<<24); + Uint32 headersize=hdr[16]|(hdr[17]<<8)|(hdr[18]<<16)|(hdr[19]<<24); + Uint32 cryptlength=hdr[20]|(hdr[21]<<8)|(hdr[22]<<16)|(hdr[23]<<24); + if(!strncmp("GGA00000",(char*)hdr,8) && width>0 && height>0){ + // Copy source data to memory + int srclen=Object->Seek(0,SEEK_END); + int dstlen=width*height*4; + unsigned char *dstbuf=new unsigned char[dstlen]; + unsigned char *srcbuf=new unsigned char[srclen]; + Object->Seek(0,SEEK_SET); + Object->Read(srcbuf,srclen); + + // Note on per-pixel alpha gga's + // + // GGA is a per-pixel format, but these are sometimes all set to + // opaque, awaiting a per-surface blend which SDL cannot do when + // the per-pixel values are set. Hence we make a opaque surface if + // all values are set to opaque. + bool opaque_ff=true; + bool opaque_00=true; + + // Decode data + Uint8 ctrl; + unsigned char arr[4]; + int tpos1,tpos2,opos=0,ipos=headersize; + while(ipos-headersize0;j--){ + dstbuf[opos++]=arr[0]; + dstbuf[opos++]=arr[1]; + dstbuf[opos++]=arr[2]; + dstbuf[opos++]=arr[3]; + } + } + else if(ctrl==0x01){ + opos-=4; + arr[0]=dstbuf[opos++]; + arr[1]=dstbuf[opos++]; + arr[2]=dstbuf[opos++]; + arr[3]=dstbuf[opos++]; + Uint8 h=srcbuf[ipos++]; + Uint8 l=srcbuf[ipos++]; + Uint16 len=(l<<8)|h; + for(int j=len;j>0;j--){ + dstbuf[opos++]=arr[0]; + dstbuf[opos++]=arr[1]; + dstbuf[opos++]=arr[2]; + dstbuf[opos++]=arr[3]; + } + } + else if(ctrl==0x02){ + tpos1=opos; + Uint16 i=srcbuf[ipos++]; + opos=opos-(i<<2); + arr[0]=dstbuf[opos++]; + arr[1]=dstbuf[opos++]; + arr[2]=dstbuf[opos++]; + arr[3]=dstbuf[opos++]; + opos=tpos1; + dstbuf[opos++]=arr[0]; + dstbuf[opos++]=arr[1]; + dstbuf[opos++]=arr[2]; + dstbuf[opos++]=arr[3]; + } + else if(ctrl==0x03){ + Uint8 h=srcbuf[ipos++]; + Uint8 l=srcbuf[ipos++]; + Uint32 i=(l<<8)|h; + tpos1=opos; + opos=opos-(i<<2); + arr[0]=dstbuf[opos++]; + arr[1]=dstbuf[opos++]; + arr[2]=dstbuf[opos++]; + arr[3]=dstbuf[opos++]; + opos=tpos1; + dstbuf[opos++]=arr[0]; + dstbuf[opos++]=arr[1]; + dstbuf[opos++]=arr[2]; + dstbuf[opos++]=arr[3]; + } + else if(ctrl==0x04){ + Uint8 l=srcbuf[ipos++]; + tpos2=opos-(l<<2); + Uint8 len=srcbuf[ipos++]; + for(int j=len;j>0;j--){ + tpos1=opos; + opos=tpos2; + tpos2+=4; + arr[0]=dstbuf[opos++]; + arr[1]=dstbuf[opos++]; + arr[2]=dstbuf[opos++]; + arr[3]=dstbuf[opos++]; + opos=tpos1; + dstbuf[opos++]=arr[0]; + dstbuf[opos++]=arr[1]; + dstbuf[opos++]=arr[2]; + dstbuf[opos++]=arr[3]; + } + } + else if(ctrl==0x05){ + Uint8 l=srcbuf[ipos++]; + tpos2=opos-(l<<2); + Uint8 h=srcbuf[ipos++]; + l=srcbuf[ipos++]; + Uint16 len=(l<<8)|h; + for(int j=len;j>0;j--){ + tpos1=opos; + opos=tpos2; + tpos2+=4; + arr[0]=dstbuf[opos++]; + arr[1]=dstbuf[opos++]; + arr[2]=dstbuf[opos++]; + arr[3]=dstbuf[opos++]; + opos=tpos1; + dstbuf[opos++]=arr[0]; + dstbuf[opos++]=arr[1]; + dstbuf[opos++]=arr[2]; + dstbuf[opos++]=arr[3]; + } + } + else if(ctrl==0x06){ + Uint8 h=srcbuf[ipos++]; + Uint8 l=srcbuf[ipos++]; + Uint32 i=(l<<8)|h; + tpos2=opos-(i<<2); + Uint8 len=srcbuf[ipos++]; + for(int j=len;j>0;j--){ + tpos1=opos; + opos=tpos2; + tpos2+=4; + arr[0]=dstbuf[opos++]; + arr[1]=dstbuf[opos++]; + arr[2]=dstbuf[opos++]; + arr[3]=dstbuf[opos++]; + opos=tpos1; + dstbuf[opos++]=arr[0]; + dstbuf[opos++]=arr[1]; + dstbuf[opos++]=arr[2]; + dstbuf[opos++]=arr[3]; + } + } + else if(ctrl==0x07){ + Uint8 h=srcbuf[ipos++]; + Uint8 l=srcbuf[ipos++]; + Uint32 i=(l<<8)|h; + tpos2=opos-(i<<2); + h=srcbuf[ipos++]; + l=srcbuf[ipos++]; + i=(l<<8)|h; + for(int j=i;j>0;j--){ + tpos1=opos; + opos=tpos2; + tpos2+=4; + arr[0]=dstbuf[opos++]; + arr[1]=dstbuf[opos++]; + arr[2]=dstbuf[opos++]; + arr[3]=dstbuf[opos++]; + opos=tpos1; + dstbuf[opos++]=arr[0]; + dstbuf[opos++]=arr[1]; + dstbuf[opos++]=arr[2]; + dstbuf[opos++]=arr[3]; + } + } + else if(ctrl==0x08){ + tpos1=opos; + opos-=4; + arr[0]=dstbuf[opos++]; + arr[1]=dstbuf[opos++]; + arr[2]=dstbuf[opos++]; + arr[3]=dstbuf[opos++]; + opos=tpos1; + dstbuf[opos++]=arr[0]; + dstbuf[opos++]=arr[1]; + dstbuf[opos++]=arr[2]; + dstbuf[opos++]=arr[3]; + } + else if(ctrl==0x09){ + tpos1=opos; + opos-=(width*4); + arr[0]=dstbuf[opos++]; + arr[1]=dstbuf[opos++]; + arr[2]=dstbuf[opos++]; + arr[3]=dstbuf[opos++]; + opos=tpos1; + dstbuf[opos++]=arr[0]; + dstbuf[opos++]=arr[1]; + dstbuf[opos++]=arr[2]; + dstbuf[opos++]=arr[3]; + } + else if(ctrl==0x0A){ + tpos1=opos; + opos-=((width*4)+4); + arr[0]=dstbuf[opos++]; + arr[1]=dstbuf[opos++]; + arr[2]=dstbuf[opos++]; + arr[3]=dstbuf[opos++]; + opos=tpos1; + dstbuf[opos++]=arr[0]; + dstbuf[opos++]=arr[1]; + dstbuf[opos++]=arr[2]; + dstbuf[opos++]=arr[3]; + } + else if(ctrl==0x0B){ + tpos1=opos; + opos-=((width*4)-4); + arr[0]=dstbuf[opos++]; + arr[1]=dstbuf[opos++]; + arr[2]=dstbuf[opos++]; + arr[3]=dstbuf[opos++]; + opos=tpos1; + dstbuf[opos++]=arr[0]; + dstbuf[opos++]=arr[1]; + dstbuf[opos++]=arr[2]; + dstbuf[opos++]=arr[3]; + } + else{ + Uint8 len=ctrl-11; + for(int j=len;j>0;j--){ + dstbuf[opos++]=srcbuf[ipos++]; + dstbuf[opos++]=srcbuf[ipos++]; + dstbuf[opos++]=srcbuf[ipos++]; + dstbuf[opos++]=srcbuf[ipos++]; + opaque_ff&=(srcbuf[ipos-1]==0xFF); + opaque_00&=(srcbuf[ipos-1]==0x00); + } + } + } + + // Convert result to a 32bit surface while flipping colors + retval=EDL_CreateSurface(width,height); + opos=0; + for (int y=0;yformat->Rshift; + Uint32 gshift=retval->format->Gshift; + Uint32 bshift=retval->format->Bshift; + Uint32 ashift=retval->format->Ashift; + Uint32 rmask=retval->format->Rmask; + Uint32 gmask=retval->format->Gmask; + Uint32 bmask=retval->format->Bmask; + Uint32 amask=retval->format->Amask; + Uint32 b=(dstbuf[opos++]<pixels))+ + ((y*(retval->pitch/4))+x); + *pixel=r|g|b|a; + } + } + + // Clean up buffers + delete [] srcbuf; + delete [] dstbuf; + } + else{ + LogError("Invalid GGA Header"); + } + return retval; +} + +/*! \brief Decompresses and converts an 24bit GGD (Ikura games) + * \param Object Input data + * \returns Converted imagedata or NULL if failed + * + * These images are used for opaque cg in ikura games + */ +SDL_Surface *CIkura::ggd_24b(RWops *Object){ + // Extract graphic attributes + SDL_Surface *retval=0; + unsigned char hdr[8]; + Object->Seek(0,SEEK_SET); + Object->Read(hdr,8); + int width=hdr[4]|hdr[5]<<8; + int height=hdr[6]|hdr[7]<<8; + int depth=24; + if(width>0 && height>0){ + // Copy source data to memory + int srclen=Object->Seek(0,SEEK_END); + int dstlen=width*height*(depth/3); + unsigned char *dstbuf=new unsigned char[dstlen]; + unsigned char *srcbuf=new unsigned char[srclen]; + Object->Seek(0,SEEK_SET); + Object->Read(srcbuf,srclen); + + // Decompress input data + int o=0; + unsigned char buf[8]; + for(int i=8;i(retval->pixels)+ + (y*retval->pitch)+(x*retval->format->BytesPerPixel); + pixels[3]=0xFF; + pixels[2]=dstbuf[o++]; + pixels[1]=dstbuf[o++]; + pixels[0]=dstbuf[o++]; + } + } + + // Clean up buffers + delete [] srcbuf; + delete [] dstbuf; + } + else{ + LogError("Invalid GGD Header"); + } + return retval; +} + diff --git a/engines/vileVN/res/converters/cikura.h b/engines/vileVN/res/converters/cikura.h new file mode 100644 index 0000000000..f4d75d96ad --- /dev/null +++ b/engines/vileVN/res/converters/cikura.h @@ -0,0 +1,26 @@ +/*! \class CIkura + * \brief Conversion routines for Ikura GDL + */ +#ifndef _CIKURA_H_ +#define _CIKURA_H_ + +#include "../rwops.h" +#include "../../common/edl_gfx.h" + +class CIkura { + public: + // Converters + static SDL_Surface *ggp_32b(RWops *Object); + static SDL_Surface *gga_32b(RWops *Object); + static SDL_Surface *ggd_32b(RWops *Object); + static SDL_Surface *ggd_24b(RWops *Object); + static SDL_Surface *ggd_16b(RWops *Object); + static SDL_Surface *ggd_8b(RWops *Object); + static SDL_Surface **gan(RWops *Object); + + // Game-specific + static Uint32 ggd_24b_alpha; +}; + +#endif + diff --git a/engines/vileVN/res/converters/ctlove.cpp b/engines/vileVN/res/converters/ctlove.cpp new file mode 100644 index 0000000000..6d313f3b7a --- /dev/null +++ b/engines/vileVN/res/converters/ctlove.cpp @@ -0,0 +1,144 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "ctlove.h" + +SDL_Surface *CTLove::mrs(RWops *Object){ + SDL_Surface *retval=0; + if(Object){ + Uint8 hdr[12]; + Object->Seek(0,SEEK_SET); + Object->Read(hdr,12); + Uint16 w=hdr[4]|(hdr[5]<<8); + Uint16 h=hdr[6]|(hdr[7]<<8); + bool test1=!hdr[8] && !hdr[9] && !hdr[10] && !hdr[11]; + bool test2=hdr[1]=='D' || hdr[1]=='O'; + if(hdr[0]==0x43 && hdr[2]==0 && hdr[3]==0 && test1 && test2){ + // Parse palette + Uint16 colors=hdr[1]=='D'?16:256; + Uint8 palette[0x300]; + if(Object->Read(palette,0x300)==0x300){ + // Parse data + int c=Object->Size()-Object->Tell(); + if(c>0){ + Uint8 inbuffer[c]; + if(Object->Read(inbuffer,c)==c){ + // Decode input + unsigned int s=w*h; + Uint8 outbuffer[s]; + Uint8 *dst=outbuffer; + Uint8 *dste=outbuffer+s; + Uint8 *src=inbuffer; + Uint8 *srce=inbuffer+c; + while((dst>4)&0xF; + if(tmp){ + tmp+=2; + } + else{ + tmp=(*src++)+0x0A; + } + if(dst+tmp>dste){ + tmp=dste-dst; + } + while(tmp--){ + Uint8 byte=dst[-offset-1]; + *dst++=byte; + } + } + else if(tmp&0x40){ + // RLE + tmp&=~0x40; + if(!tmp){ + tmp=(*src++)+0x40; + } + tmp++; + if(dst+tmp>dste){ + tmp=dste-dst; + } + memset(dst,dst[-1],tmp); + dst+=tmp; + } + else{ + // Uncompressed + if(!tmp){ + tmp=(*src++)+0x40; + } + if(dst+tmp>dste){ + tmp=dste-dst; + } + while(tmp--){ + *dst++=*src++; + } + } + } + + // Convert to surface + retval=EDL_CreateSurface(w,h); + if(SDL_MUSTLOCK(retval)){ + if(SDL_LockSurface(retval)<0){ + return 0; + } + } + Uint8 r=0x00; + Uint8 g=0x00; + Uint8 b=0x00; + Uint8 a=0xFF; + unsigned int k=0; + for(unsigned int l=0;l0x300){ + LogTest("16:%d:%d:%d:%d",p,r,g,b); + } + } + if(colors==256){ + LogError("256b MSR decoding not supported"); + SDL_FreeSurface(retval); + return 0; + } + + + // Set bitmap pixel + Uint8 *pixels=static_cast + (retval->pixels)+ + (l*retval->pitch)+ + (m*retval->format->BytesPerPixel); + pixels[0]=r; + pixels[1]=g; + pixels[2]=b; + pixels[3]=a; + } + } + if(SDL_MUSTLOCK(retval)){ + SDL_UnlockSurface(retval); + } + } + } + } + } + } + return retval; +} + diff --git a/engines/vileVN/res/converters/ctlove.h b/engines/vileVN/res/converters/ctlove.h new file mode 100644 index 0000000000..2f20263ce9 --- /dev/null +++ b/engines/vileVN/res/converters/ctlove.h @@ -0,0 +1,15 @@ +/*! \class CTLove + * \brief Conversion routines for Truelove Engine + */ +#ifndef _CTLOVE_H_ +#define _CTLOVE_H_ + +#include "../rwops.h" +#include "../../common/edl_gfx.h" + +class CTLove { + public: + static SDL_Surface *mrs(RWops *Object); +}; + +#endif diff --git a/engines/vileVN/res/converters/cwill.cpp b/engines/vileVN/res/converters/cwill.cpp new file mode 100644 index 0000000000..2845d0a65b --- /dev/null +++ b/engines/vileVN/res/converters/cwill.cpp @@ -0,0 +1,210 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "cwill.h" + +/*! \brief Decodes WIPF images (First frame in multipicture files) + * \param Object Resource blob to decode + * \return Decoded surface + */ +SDL_Surface *CWill::wip(RWops *Object){ + return wip(Object,0); +} + +/*! \brief Decodes collection WIPF images + * \param Object Resource blob to decode + * \return Array of decoded surfaces + */ +SDL_Surface **CWill::wipa(RWops *Object){ + SDL_Surface **retval=0; + if(Object){ + Uint8 hdr[24]; + Object->Seek(0,SEEK_SET); + Object->Read(hdr,8); + unsigned int count=hdr[4]|(hdr[5]<<8); + //unsigned int bpp=hdr[6]|(hdr[7]<<8); + if(hdr[0]=='W' && hdr[1]=='I' && hdr[2]=='P' && hdr[3]=='F' && count){ + retval=new SDL_Surface*[count+1]; + for(unsigned int i=0;iSeek(0,SEEK_SET); + Object->Read(hdr,8); + unsigned int count=hdr[4]|(hdr[5]<<8); + unsigned int bpp=hdr[6]|(hdr[7]<<8); + if(hdr[0]=='W' && hdr[1]=='I' && hdr[2]=='P' && hdr[3]=='F' && count){ + unsigned int palettesize=0; + if(bpp==8){ + palettesize=256*4; + } + unsigned int indexpos=8; + unsigned int datapos=8+(count*24); + for(unsigned int i=0;iRead(hdr,24)==24;i++){ + unsigned int w=hdr[0]|(hdr[1]<<8)|(hdr[2]<<16)|(hdr[3]<<24); + unsigned int h=hdr[4]|(hdr[5]<<8)|(hdr[6]<<16)|(hdr[7]<<24); + unsigned int c=hdr[20]|(hdr[21]<<8)|(hdr[22]<<16)|(hdr[23]<<24); + unsigned int s=w*h*(bpp/8); + + // Reseek to datapos and roll indexes + int curpos=datapos; + indexpos+=24; + datapos+=c; + datapos+=palettesize; + + // Skip unrelated data + if(Index!=(int)i){ + continue; + } + + // Read palette + Object->Seek(curpos,SEEK_SET); + Uint8 *palette=0; + if(bpp==8){ + palette=new Uint8[palettesize]; + Object->Read(palette,palettesize); + } + + // Prepp input/output + Uint8 *outbuffer=new Uint8[s]; + Uint8 *inbuffer=new Uint8[c]; + if(Object->Read(inbuffer,c)==(int)c){ + // LZ decoding (Thanks to Animed 0.6.8.141) + Uint32 SlidWindowIndex=0x1; + Uint32 SlidWindowLength=0xFFF; + Uint8 SlidingWindow[SlidWindowLength+1]; + for(unsigned int j=0;j<=SlidWindowLength;j++){ + SlidingWindow[j]=0; + } + unsigned int Temp1=0; + unsigned int Temp2=0; + unsigned int in=0; + unsigned int out=0; + Uint32 EAX,ECX,EDI; + Uint8 AL,DI; + while(c>in){ + EAX=Temp1; + EAX=EAX>>1; + Temp1=EAX; + if(((EAX & 0xFF00) & 0x100)==0){ + AL=inbuffer[in++]; + EAX=AL|0xFF00; + Temp1=EAX; + } + if(((Temp1 & 0xFF) & 0x1)!=0){ + AL=inbuffer[in++]; + outbuffer[out++]=AL; + SlidingWindow[SlidWindowIndex]=AL; + SlidWindowIndex++; + SlidWindowIndex&=SlidWindowLength; + } + else{ + DI=inbuffer[in++]; + AL=inbuffer[in++]; + EDI=((DI<<8)|AL)>>4; + EAX=(AL&0xF)+2; + Temp2=EAX; + ECX=0; + if(EAX>0){ + while(ECX=24){ + g=outbuffer[k+(w*h)]; + r=outbuffer[k+(w*h*2)]; + } + if(bpp==32){ + a=outbuffer[k+(w*h*3)]; + } + k++; + + // Set bitmap pixel + Uint8 *pixels=static_cast + (retval->pixels)+ + (l*retval->pitch)+ + (m*retval->format->BytesPerPixel); + pixels[0]=r; + pixels[1]=g; + pixels[2]=b; + pixels[3]=a; + } + } + if(SDL_MUSTLOCK(retval)){ + SDL_UnlockSurface(retval); + } + } + + // Delete palette + delete [] inbuffer; + delete [] outbuffer; + if(palette){ + delete [] palette; + palette=0; + } + + // We got what we came for ... + break; + } + } + } + return retval; +} + diff --git a/engines/vileVN/res/converters/cwill.h b/engines/vileVN/res/converters/cwill.h new file mode 100644 index 0000000000..999d7c565c --- /dev/null +++ b/engines/vileVN/res/converters/cwill.h @@ -0,0 +1,19 @@ +/*! \class CWill + * \brief Conversion routines for Windy Engine + * + * Actually converts bitmaps for the s21 engine used by the Mayclub remake + */ +#ifndef _CWILL_H_ +#define _CWILL_H_ + +#include "../rwops.h" +#include "../../common/edl_gfx.h" + +class CWill { + public: + static SDL_Surface *wip(RWops *Object,int Index); + static SDL_Surface *wip(RWops *Object); + static SDL_Surface **wipa(RWops *Object); +}; + +#endif diff --git a/engines/vileVN/res/converters/cwindy.cpp b/engines/vileVN/res/converters/cwindy.cpp new file mode 100644 index 0000000000..3ec2971652 --- /dev/null +++ b/engines/vileVN/res/converters/cwindy.cpp @@ -0,0 +1,165 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "cwindy.h" + +SDL_Surface *CWindy::bet_32b(RWops *Object){ + SDL_Surface *retval=0; + if(Object){ + // Poke the header + Uint8 magic[8]; + Uint8 rlen[8]; + Uint8 ctype; + Uint8 lastchar; + Object->Seek(0,SEEK_SET); + Object->Read(magic,8); + Object->Read(&ctype,1); + Object->Read(&lastchar,1); + Object->Read(&rlen,4); + + // Verify basic header data and ctype type + if(magic[0]=='S' && magic[1]=='Z' && + magic[2]=='D' && magic[3]=='D' && + magic[4]==0x88 && magic[5]==0xF0 && + magic[6]==0x27 && magic[7]==0x33 && + ctype=='A'){ + // Convert values + Uint32 reallength=rlen[3]<<24|rlen[2]<<16|rlen[1]<<8|rlen[0]; + Uint32 stringlen=0; + Uint32 stringpos=0; + + // Prepp target + Uint8 *tbuffer=new Uint8[reallength]; + Uint32 tindex=0; + + // Prepare table + Uint8 table[0x1000]={0x20}; + Uint32 curtabent=0xFF0; + Uint16 bytetype=0; + + // Decompress using microsofts SZDD algorithm + while(tindexRead(&b,1)){ + break; + } + bytetype=b|0xFF00; + } + if(bytetype&1){ + if (1!=Object->Read(&b,1)){ + break; + } + } + else{ + Uint8 b1,b2; + if (1!=Object->Read(&b1,1)) break; + if (1!=Object->Read(&b2,1)) break; + + /* Format: + * b1 b2 + * AB CD + * where CAB is the stringoffset in the table + * and D+3 is the len of the string + */ + stringpos=b1|((b2&0xf0)<<4); + stringlen=(b2&0xf)+2; + + /* 3, but we use a byte already below ... */ + b=table[stringpos]; + stringpos=(stringpos+1)&0xFFF; + } + bytetype>>=1; + } + + /* store b in table */ + table[curtabent++]=b; + curtabent&=0xFFF; + tbuffer[tindex++]=b; + } + + // Extract special header + Uint32 w=tbuffer[3]<<24|tbuffer[2]<<16|tbuffer[1]<<8|tbuffer[0]; + Uint32 h=tbuffer[7]<<24|tbuffer[6]<<16|tbuffer[5]<<8|tbuffer[4]; + Uint16 d=tbuffer[9]<<8|tbuffer[8]; + tindex=10; + if(d==24){ + // Convert result to a 32bit surface while flipping colors + retval=EDL_CreateSurface(w,h); + Uint32 rshift=retval->format->Rshift; + Uint32 gshift=retval->format->Gshift; + Uint32 bshift=retval->format->Bshift; + Uint32 ashift=retval->format->Ashift; + Uint32 rmask=retval->format->Rmask; + Uint32 gmask=retval->format->Gmask; + Uint32 bmask=retval->format->Bmask; + Uint32 amask=retval->format->Amask; + for (unsigned int y=h;y>0;y--){ + for (unsigned int x=0;xpixels))+ + (((y-1)*(retval->pitch/4))+x); + *pixel=r|g|b|a; + } + } + } + else if(d==8){ + // Drop palette + Uint32 pindex=tindex; + tindex+=1024; + retval=EDL_CreateSurface(w,h); + Uint32 rshift=retval->format->Rshift; + Uint32 gshift=retval->format->Gshift; + Uint32 bshift=retval->format->Bshift; + Uint32 ashift=retval->format->Ashift; + Uint32 rmask=retval->format->Rmask; + Uint32 gmask=retval->format->Gmask; + Uint32 bmask=retval->format->Bmask; + Uint32 amask=retval->format->Amask; + for (unsigned int y=h;y>0;y--){ + for (unsigned int x=0;xpixels))+ + (((y-1)*(retval->pitch/4))+x); + *pixel=r|g|b|a; + } + } + } + else{ + LogError("Invalid bitlength for BET: %d",d); + } + delete [] tbuffer; + } + } + return retval; +} + diff --git a/engines/vileVN/res/converters/cwindy.h b/engines/vileVN/res/converters/cwindy.h new file mode 100644 index 0000000000..4e53e12449 --- /dev/null +++ b/engines/vileVN/res/converters/cwindy.h @@ -0,0 +1,17 @@ +/*! \class CWindy + * \brief Conversion routines for Windy Engine + * + * Actually converts bitmaps for the s21 engine used by the Mayclub remake + */ +#ifndef _CWINDY_H_ +#define _CWINDY_H_ + +#include "../rwops.h" +#include "../../common/edl_gfx.h" + +class CWindy { + public: + static SDL_Surface *bet_32b(RWops *Object); +}; + +#endif diff --git a/engines/vileVN/res/media.cpp b/engines/vileVN/res/media.cpp new file mode 100644 index 0000000000..ad4b950444 --- /dev/null +++ b/engines/vileVN/res/media.cpp @@ -0,0 +1,67 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "media.h" + +Resources *Media::resman=0; + +/*! \brief Closes the internal resources + * + * This method should be called when shutting down the application to keep + * valgrind happy :) + */ +void Media::Close(){ + if(resman){ + delete resman; + resman=0; + } +} + +/*! \brief Loads an internal resource + * \param Name Name of the resources you want to load + * \return RWops containing the extracted resource + */ +RWops *Media::GetResource(uString Name){ + if(!resman){ + resman=new Resources(); + resman->AddResource(new ArchiveViLE(Cfg::Path::resource)); + } + return resman->GetResource(Name); +} + +/*! \brief Loads an image from the internal resource + * \param Name Name of the image you want to load + * \return SDL_surface with the decoded imagedata + */ +SDL_Surface *Media::GetImage(uString Name){ + if(!resman){ + resman=new Resources(); + resman->AddResource(new ArchiveViLE(Cfg::Path::resource)); + } + return resman->GetImage(Name); +} + +/*! \brief Loads an animation from the internal resource + * \param Name Name of the animation you want to load + * \return Array of SDL_surfaces with decoded imagedata + */ +SDL_Surface **Media::GetAnimation(uString Name){ + if(!resman){ + resman=new Resources(); + resman->AddResource(new ArchiveViLE(Cfg::Path::resource)); + } + return resman->GetAnimation(Name); +} + diff --git a/engines/vileVN/res/media.h b/engines/vileVN/res/media.h new file mode 100644 index 0000000000..eb5cc91440 --- /dev/null +++ b/engines/vileVN/res/media.h @@ -0,0 +1,29 @@ +/*! \class Media + * \brief Provides media from the standard resource file + * + * The internal resource archive (Default:vilevn.pck) contains standard + * graphic templates for standard widgets such as checkboxes, buttons and + * sliders. + * + * Internal resources are globally available. + */ + +#ifndef _MEDIA_H_ +#define _MEDIA_H_ + +#include "resources.h" + +class Media{ + private: + static Resources *resman; + public: + // Resource and conversion interface + static RWops *GetResource(uString Name); + static SDL_Surface *GetImage(uString Name); + static SDL_Surface **GetAnimation(uString Name); + static void Close(); +}; + +#endif + + diff --git a/engines/vileVN/res/resources.cpp b/engines/vileVN/res/resources.cpp new file mode 100644 index 0000000000..618b0f5a25 --- /dev/null +++ b/engines/vileVN/res/resources.cpp @@ -0,0 +1,470 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "resources.h" + +Resources::Resources(){ + stack=0; +} + +Resources::~Resources(){ + // Release indexed archives + while(stack){ + ArchiveBase *tmpptr=stack->NextPtr; + delete stack; + stack=tmpptr; + } +} + +/*! \brief Autodetects and opens an archive + * \param Path Path to archive resource + * + * Game implementations should preopen the archive manually before adding + * it to assert archive type and reduce the overhead at boot-time. This is + * intended as a convenience function for the commandline tools. + */ +int Resources::AddResource(uString Path){ + uString Filename=EDL_Realname(Path); + ArchiveBase *testarc=0; +#ifdef VILE_SUPPORT_WINDY + // Attempt to open the archive as windy format + if(!testarc){ + testarc=new ArchiveWindy(Filename); + if(testarc->GetCount()){ + LogVerbose("Opened %s as a Windy archive",Filename.c_str()); + } + else{ + if(testarc) delete testarc; + testarc=0; + } + } + + // Attempt to open the archive in system21 format + if(!testarc){ + testarc=new ArchiveS21(Filename); + if(testarc->GetCount()){ + LogVerbose("Opened %s as a System21 archive",Filename.c_str()); + } + else{ + if(testarc) delete testarc; + testarc=0; + } + } +#endif + +#ifdef VILE_SUPPORT_JAST + // Attempt to open the archive in JAST USA format + if(!testarc){ + testarc=new ArchiveJAST(Filename); + if(testarc->GetCount()){ + LogVerbose("Opened %s as a JAST archive",Filename.c_str()); + } + else{ + if(testarc) delete testarc; + testarc=0; + } + } +#endif + +#ifdef VILE_SUPPORT_CWARE + // Attempt to open the archive in CWare format + if(!testarc){ + testarc=new ArchiveCWareDL1(Filename); + if(testarc->GetCount()){ + LogVerbose("Opened %s as a CWare DL1 archive",Filename.c_str()); + } + else{ + if(testarc) delete testarc; + testarc=0; + } + } + if(!testarc){ + testarc=new ArchiveCWareARC2(Filename); + if(testarc->GetCount()){ + LogVerbose("Opened %s as CWare ARC2",Filename.c_str()); + } + else{ + if(testarc) delete testarc; + testarc=0; + } + } +#endif + +#ifdef VILE_SUPPORT_WILL + // Attempt to open the archive in WILL formats + if(!testarc){ + testarc=new ArchiveWillARC(Filename); + if(testarc->GetCount()){ + LogVerbose("Opened %s as a Will ARC archive",Filename.c_str()); + } + else{ + if(testarc) delete testarc; + testarc=0; + } + } +#endif + +#ifdef VILE_SUPPORT_TLOVE + // Attempt to open the archive as True love cabinet + if(!testarc){ + testarc=new ArchiveTLove(Filename); + if(testarc->GetCount()){ + LogVerbose("Opened %s as a Truelove archive",Filename.c_str()); + } + else{ + if(testarc) delete testarc; + testarc=0; + } + } +#endif + +#ifdef VILE_SUPPORT_IKURA + // Attempt to open the archive as IkuraGDL format + //! \todo Improve type-testing of IkuraGDL format + if(!testarc){ + testarc=new ArchiveIkura(Filename); + if(testarc->GetCount()){ + LogVerbose("Opened %s as a IkuraGDL archive",Filename.c_str()); + } + else{ + if(testarc) delete testarc; + testarc=0; + } + } +#endif + +#ifdef VILE_SUPPORT_CROWD + // Attempt to open the archive as Crowd SCE format + //! \todo Improve type-testing of Crowd SCE format + if(!testarc){ + testarc=new ArchiveCrowdSCE(Filename); + if(testarc->GetCount()){ + LogVerbose("Opened %s as a Crowd SCE archive",Filename.c_str()); + } + else{ + if(testarc) delete testarc; + testarc=0; + } + } + + // Attempt to open the archive as Crowd PCK format + if(!testarc){ + testarc=new ArchiveCrowdPCK(Filename); + if(testarc->GetCount()){ + LogVerbose("Opened %s as a Crowd PCK archive",Filename.c_str()); + } + else{ + if(testarc) delete testarc; + testarc=0; + } + } + + // Attempt to open the archive as Crowd SNN format + if(!testarc){ + testarc=new ArchiveCrowdSNN(Filename); + if(testarc->GetCount()){ + LogVerbose("Opened %s as a Crowd SNN archive",Filename.c_str()); + } + else{ + if(testarc) delete testarc; + testarc=0; + } + } +#endif + + // Attempt to open as native ViLE cabinet + if(!testarc){ + testarc=new ArchiveViLE(Filename); + if(testarc->GetCount()){ + LogVerbose("Opened %s as a ViLE archive",Filename.c_str()); + } + else{ + if(testarc) delete testarc; + testarc=0; + } + } + + // Register as file + if(!testarc){ + testarc=new ArchiveFiles(Filename); + } + return AddResource(testarc); +} + +/*! \brief Registers a preloaded archive + * \param Archive Archive object to register + */ +int Resources::AddResource(ArchiveBase *Archive){ + int retval=Archive?Archive->GetCount():0; + if(retval){ + if(stack){ + ArchiveBase *tmpptr=stack; + while(tmpptr->NextPtr){ + tmpptr=tmpptr->NextPtr; + } + tmpptr->NextPtr=Archive; + } + else{ + stack=Archive; + } + Archive->NextPtr=0; + } + else if(Archive){ + delete Archive; + } + return retval; +} + +/*! \brief Get the best available resource + * \param Name of the desired resource (With extension if applicable + * \returns RWops with raw data + * + * This method will try to locate the given resource in a prioritized + * sequence. The returned data will be in its raw form, and should usually + * be decoded by a specialized method in one of the derived classes. + */ +RWops *Resources::GetResource(uString Name){ + // Search stacked archives + RWops *retval=0; + ArchiveBase *tmpptr=stack; + while(retval==0 && tmpptr){ + retval=tmpptr->GetResource(Name); + tmpptr=tmpptr->NextPtr; + } + return retval; +} + +/*! \brief Writes out the allocated contents to a ViLE cabinet + * \param Archive Filename to write (Existing files will be overwritten) + * \return True if any resources was written to the archive + */ +bool Resources::Write(uString Archive){ + bool retval=false; + Stringlist list; + if(EnumerateResources(&list)>0){ + int count=list.GetCount(); + FILE *file=fopen(Archive.c_str(),"wb"); + if(file){ + // Write temporary header + unsigned int length=16+(32*list.GetCount()); + unsigned char *table=new unsigned char[length]; + memset(table,0,length); + strcpy((char*)table,"ViLEPACK"); + table[12]=length&0xFF; + table[13]=(length>>8)&0xFF; + table[14]=(length>>16)&0xFF; + table[15]=(length>>24)&0xFF; + fwrite(table,length,1,file); + + // TODO: Write items + unsigned int offset=length; + for(int i=0;iSize()){ + // Format the name for the table + uString n=EDL_FileName(name); + uString e=EDL_FileExtension(name); + if(e.length()){ + n+="."; + n+=e; + } + if(n.length()>24){ + n=n.substr(0,24); + } + + // Store resource + unsigned int size=resource->Size(); + unsigned char *buffer=new unsigned char[size]; + if(resource->Read(buffer,size)>0){ + // Store position and size + strcpy((char*)table+(i*32)+16,n.c_str()); + table[(i*32)+16+24]=offset&0xFF; + table[(i*32)+16+25]=(offset>>8)&0xFF; + table[(i*32)+16+26]=(offset>>16)&0xFF; + table[(i*32)+16+27]=(offset>>24)&0xFF; + table[(i*32)+16+28]=size&0xFF; + table[(i*32)+16+29]=(size>>8)&0xFF; + table[(i*32)+16+30]=(size>>16)&0xFF; + table[(i*32)+16+31]=(size>>24)&0xFF; + + // Update output file + LogMessage("Storing %s from %d to %d", + name.c_str(),offset,offset+size); + fwrite(buffer,size,1,file); + offset+=size; + } + else{ + strcpy((char*)table+(i*32)+16,"ERROR"); + } + delete [] buffer; + delete resource; + } + else{ + LogError("Invalid resource %d: %s",i,name.c_str()); + } + } + + // TODO: Wrap up cabinet + fseek(file,0,SEEK_SET); + fwrite(table,length,1,file); + fclose(file); + delete [] table; + } + else{ + LogError("Failed to write: %s",Archive.c_str()); + } + } + else{ + LogError("No resources to write"); + } + return retval; +} + +/*! \brief Enumerates all loaded archives + * \param Pointer to stringlist for the results + * \return Number of archives + */ +int Resources::EnumerateArchives(Stringlist *List){ + *List=list; + return list.GetCount(); +} + +/*! \brief Enumerates all available resources + * \param Pointer to stringlist for the results + * \return Number of resources added + */ +int Resources::EnumerateResources(Stringlist *List){ + // Iterate stacked archives + int retval=0; + ArchiveBase *tmpptr=stack; + while(tmpptr){ + retval+=tmpptr->Enumerate(List); + tmpptr=tmpptr->NextPtr; + } + return retval; +} + +SDL_Surface *Resources::GetImage(uString Name){ + // Get resource and convert it to an image + unsigned char h[4]; + SDL_Surface *retval=0; + RWops *blob=GetResource(Name); + if(blob && blob->Read(h,4)>(int)0){ + // Reseek for SDL_image autodetection + blob->Seek(0,SEEK_SET); + +#ifdef VILE_SUPPORT_CROWD + // Check for Crowd CWP content + if(!retval && h[0]=='C' && h[1]=='W' && h[2]=='D' && h[3]=='P'){ + retval=CCrowd::cwp(blob); + } + if(!retval && h[0]==0x53 && h[1]==0x5A && h[2]==0x44 && h[3]==0x44){ + retval=CCrowd::zbm(blob); + } +#endif + +#ifdef VILE_SUPPORT_IKURA + // Check for Ikura content + if(!retval && h[0]==0xB9 && h[1]==0xAA && h[2]==0xB3 && h[3]==0xB3){ + retval=CIkura::ggd_24b(blob); + } + if(!retval && h[0]==0xAB && h[1]==0xAD && h[2]==0xAA && h[3]==0xBA){ + retval=CIkura::ggd_24b(blob); + } + if(!retval && h[0]==0xB7 && h[1]==0xB6 && h[2]==0xB8 && h[3]==0xB7){ + retval=CIkura::ggd_24b(blob); + } + if(!retval && h[0]==0xCD && h[1]==0xCA && h[2]==0xC9 && h[3]==0xB8){ + retval=CIkura::ggd_8b(blob); + } + if(!retval && h[0]==0x47 && h[1]==0x47 && h[2]==0x41 && h[3]==0x30){ + retval=CIkura::gga_32b(blob); + } + if(!retval && h[0]==0x47 && h[1]==0x47 && h[2]=='P' && h[3]=='F'){ + retval=CIkura::ggp_32b(blob); + } +#endif + +#ifdef VILE_SUPPORT_WINDY + // Check for Windy content + if(!retval && h[0]==0x53 && h[1]==0x5A && h[2]==0x44 && h[3]==0x44){ + retval=CWindy::bet_32b(blob); + } +#endif + +#ifdef VILE_SUPPORT_CWARE + // Check for CWare content + if(!retval && h[0]==0x4C && h[1]==0x5A){ + retval=CCWare::lz_32b(blob); + } +#endif + +#ifdef VILE_SUPPORT_WILL + // Check for Will content + if(!retval && h[0]==0x57 && h[1]==0x49 && h[2]==0x50 && h[3]==0x46){ + retval=CWill::wip(blob); + } +#endif + +#ifdef VILE_SUPPORT_TLOVE + // Check for Truelove content + if(!retval && h[0]==0x43 && h[1]==0x44 && h[2]==0x00 && h[3]==0x00){ + retval=CTLove::mrs(blob); + } + if(!retval && h[0]==0x43 && h[1]==0x4F && h[2]==0x00 && h[3]==0x00){ + retval=CTLove::mrs(blob); + } +#endif + + // Check for standard formats + if(!retval){ + retval=IMG_Load_RW(blob->ops,0); + } + } + + // Free input + if(blob){ + delete blob; + } + return retval; +} + +SDL_Surface **Resources::GetAnimation(uString Name){ + unsigned char h[4]; + SDL_Surface **retval=0; + RWops *blob=GetResource(Name); + if(blob && blob->Read(h,4)>(int)0){ + blob->Seek(0,SEEK_SET); +#ifdef VILE_SUPPORT_IKURA + if(!retval && h[0]=='G' && h[1]=='A' && h[2]=='N' && h[3]=='M'){ + retval=CIkura::gan(blob); + } +#endif + +#ifdef VILE_SUPPORT_WILL + if(!retval && h[0]==0x57 && h[1]==0x49 && h[2]==0x50 && h[3]==0x46){ + retval=CWill::wipa(blob); + } +#endif + } + + if(blob){ + delete blob; + } + + return retval; +} + diff --git a/engines/vileVN/res/resources.h b/engines/vileVN/res/resources.h new file mode 100644 index 0000000000..c6dd9ee8e0 --- /dev/null +++ b/engines/vileVN/res/resources.h @@ -0,0 +1,71 @@ +/*! \class Resources + * \brief Resource Manager + * + * The resource manager keeps track of archives, and helps index and access the + * resources within them. It also collects the format conversion routines and + * allows extracting the resources as formatted, native datatypes. + * + * The resource manager is usually not accessed directly but through a driver + * class such as Media or EngineVN which defines types of resources (Like + * voices, sound effects, music, etc) and distributes them accordingly. + */ + +#ifndef _RESOURCES_H_ +#define _RESOURCES_H_ + +// Include necessary datatypes +#include +#include + +// Include archive classes +#include "archives/afiles.h" +#include "archives/avile.h" +#include "archives/awindy.h" +#include "archives/as21.h" +#include "archives/ajast.h" +#include "archives/acrowdsce.h" +#include "archives/acrowdpck.h" +#include "archives/acrowdsnn.h" +#include "archives/aikura.h" +#include "archives/acwaredl1.h" +#include "archives/acwarearc2.h" +#include "archives/awillarc.h" +#include "archives/atlove.h" + +// Include converters +#include "converters/cikura.h" +#include "converters/ccrowd.h" +#include "converters/cwindy.h" +#include "converters/ccware.h" +#include "converters/cwill.h" +#include "converters/ctlove.h" + + +class Resources +{ + private: + Stringlist list; //!< Tracks source archives + ArchiveBase *stack; //!< Tracks indexed archives + public: + // We need a constructor to set defaults + Resources(); + ~Resources(); + + // Getters and setters for resources + int AddResource(uString Path); + int AddResource(ArchiveBase *Archive); + int EnumerateArchives(Stringlist *List); + int EnumerateResources(Stringlist *List); + + // Resource and conversion interface + RWops *GetResource(uString Name); + SDL_Surface *GetImage(uString Name); + SDL_Surface **GetAnimation(uString Name); + + // Write all resources as a ViLE cabinet + bool Write(uString Archive); +}; + +#endif + + diff --git a/engines/vileVN/res/rwops.cpp b/engines/vileVN/res/rwops.cpp new file mode 100644 index 0000000000..709cc63bf7 --- /dev/null +++ b/engines/vileVN/res/rwops.cpp @@ -0,0 +1,295 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "rwops.h" + +/*! \brief Opens an empty, generic resource blob + */ +RWops::RWops(){ + type=RW_NONE; + buffer=0; + size=0; + offset=0; + ops=0; +} + +/*! \brief Makes sure that the resource is closed before exiting + */ +RWops::~RWops(){ + Close(); +} + +/*! \brief Opens a resource from an existing RWops objects + * \param Ops Blob to use as source + * \param FreeSource Original source is deleted if true + * \return True if resource could be opened + */ +bool RWops::OpenRW(RWops *Ops,bool FreeSource){ + if(Ops){ + return OpenRW(Ops,0,Ops->Size(),FreeSource); + } + else{ + return false; + } +} + +/*! \brief Opens a partial resource from an existing RWops objects + * \param Ops Blob to use as source + * \param Offset Byte offset of resource + * \param Size Size of the resource in bytes + * \param FreeSource Original source is deleted if true + * \return True if resource could be opened + */ +bool RWops::OpenRW(RWops *Ops,int Offset,int Size,bool FreeSource){ + bool retval=false; + if(Ops && Ops!=this){ + Close(); + if(Ops->type==RW_NONE){ + } + else if(Ops->type==RW_FILE){ + // Open as file + retval=OpenFile(Ops->filename.c_str(),Ops->offset+Offset,Size); + } + else if(FreeSource){ + // Move content before deleting blob + buffer=Ops->buffer; + offset=Ops->offset; + size=Ops->size; + type=Ops->type; + Ops->buffer=0; + Ops->offset=0; + Ops->size=0; + Ops->type=RW_NONE; + retval=size; + } + else if(Ops->size>=Offset+Size && Size>0){ + // Copy content + char *b=new char[Size]; + Ops->Seek(Offset,SEEK_SET); + Ops->Read(buffer,Size); + retval=OpenRAM(b,Size,false); + } + + // Close source + if(FreeSource){ + delete Ops; + } + } + return retval; +} + +/*! \brief Opens a partial file + * \param Filename Path to the file to open + * \param Offset Byte offset of resource + * \param Size Size of the resource in bytes + * \return True if resource could be opened + * + * Partial file resources is always read-only + */ +bool RWops::OpenFile(const char *Filename,int Offset,int Size){ + Close(); + if(OpenFile(Filename,"rb")){ + if(size>=Offset+Size){ + size=Size; + offset=Offset; + Seek(0,SEEK_SET); + } + else{ + Close(); + } + } + return ops; +} + +/*! \brief Opens a while file as a resource + * \param Filename Path to the file to open + * \param Offset Byte offset of resource + * \param Size Size of the resource in bytes + * \return True if resource could be opened + */ +bool RWops::OpenFile(const char *Filename,const char *Filemode){ + Close(); + if((ops=SDL_RWFromFile(Filename,Filemode))){ + size=SDL_RWseek(ops,0,SEEK_END); + Seek(0,SEEK_SET); + filename=Filename; + type=RW_FILE; + } + return ops; +} + +/*! \brief Opens a read-only memory resource + * \param Memory Source memory address + * \param Size Size of the resource in bytes + * \param FreeSource Original source is deleted if true + * \return True if resource could be opened + */ +bool RWops::OpenROM(const char *Memory,int Size,bool FreeSource){ + Close(); + if(FreeSource){ + // Use memory buffer instead of deleting it + if((ops=SDL_RWFromConstMem(Memory,Size))){ + buffer=(void*)Memory; + size=Size; + type=RW_ROBUFFER; + } + } + else if(Size){ + // Copy buffer and call it recursively + char *b=new char[Size]; + for(int i=0;isize){ + // Out of scope + } + else if(current+Size>size){ + // Limit to size + Size=size-current; + if(Size<0){ + Size=0; + } + retval=SDL_RWread(ops,Data,1,Size); + } + else{ + // Read directly + retval=SDL_RWread(ops,Data,1,Size); + } + } + return retval; +} + +/*! \brief Writes data from a target buffer + * \param Data Target buffer + * \param Size Number of bytes to write + * \return Number of bytes written (-1 indicates error) + */ +int RWops::Write(void *Data,int Size){ + int retval=-1; + if(ops){ + if(type!=RW_ROBUFFER){ + retval=SDL_RWwrite(ops,Data,1,Size); + } + else{ + retval=0; + } + if(retval>0){ + int newpos=Tell(); + if(newpos>size){ + size=newpos; + } + } + } + return retval; +} + +/*! \brief Seeks to a given position in the resource + * \param Offset Offset to seek to + * \param Whence The usual SEEK_SET/SEEK_END/SEEK_CUR specifier + * \return New offset relative to start of file + */ +int RWops::Seek(int Offset,int Whence){ + int retval=-1; + if(ops){ + if(Whence==SEEK_SET){ + retval=SDL_RWseek(ops,offset+Offset,SEEK_SET)-offset; + } + else if(Whence==SEEK_CUR){ + retval=SDL_RWseek(ops,Offset,SEEK_CUR)-offset; + } + else if(Whence==SEEK_END){ + retval=SDL_RWseek(ops,offset+size+Offset,SEEK_SET)-offset; + } + } + return retval; +} + +/*! \brief Tells the current read/write position in the resource + * \returns Byte position relative to the start of the resource + */ +int RWops::Tell(){ + int retval=-1; + if(ops){ + retval=SDL_RWtell(ops)-offset; + } + return retval; +} + +/*! \brief Tells the total size of the resource + * \returns Resource size in bytes + */ +int RWops::Size(){ + return size; +} + +/*! \brief Closes down and frees the resource data + */ +void RWops::Close(){ + if(ops){ + SDL_RWclose(ops); + } + if(buffer){ + char *tmp=(char*)buffer; + delete [] tmp; + } + filename=""; + type=RW_NONE; + offset=0; + buffer=0; + size=0; + ops=0; +} + diff --git a/engines/vileVN/res/rwops.h b/engines/vileVN/res/rwops.h new file mode 100644 index 0000000000..fcd58a2610 --- /dev/null +++ b/engines/vileVN/res/rwops.h @@ -0,0 +1,46 @@ +/*! \class RWops + * \brief Manages a blob of data while obfuscating the underlying hardware + */ +#ifndef _RWOPS_H_ +#define _RWOPS_H_ + +#include "../common/log.h" +#include "../common/edl_fs.h" + +class RWops { + private: + enum RWOPS_TYPE { //!< Defines type of data + RW_NONE=0, //!< No valid data + RW_RWBUFFER, //!< Data is in R/W ram + RW_ROBUFFER, //!< Data is in R/O ram + RW_FILE //!< Data is stored in a file + } type; //!< Type of this object + void *buffer; //!< Buffer for memory blobs + int offset; //!< Offset in stubbed blobs + int size; //!< Size of the available data + uString filename; //!< Filename for fileblobs + public: + // Oh constructors, thou art why I love oop. + RWops(); + ~RWops(); + + // Standard RW interface + bool OpenRW(RWops *Ops,bool FreeSource); + bool OpenRW(RWops *Ops,int Offset,int Size,bool FreeSource); + bool OpenFile(const char *Filename,int Offset,int Size); + bool OpenFile(const char *Filename,const char *Filemode); + bool OpenROM(const char *Memory,int Size,bool FreeSource); + bool OpenRAM(char *Memory,int Size,bool FreeSource); + int Read(void *Data,int Size); + int Write(void *Data,int Size); + int Seek(int Offset,int Whence); + int Size(); + int Tell(); + void Close(); + + //! Underlying rwops structure + SDL_RWops *ops; +}; + +#endif + diff --git a/engines/vileVN/testing/benchmark.cpp b/engines/vileVN/testing/benchmark.cpp new file mode 100644 index 0000000000..7de5475757 --- /dev/null +++ b/engines/vileVN/testing/benchmark.cpp @@ -0,0 +1,68 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "benchmark.h" + +Uint32 Benchmark::total_time=0; +Uint32 Benchmark::total_runs=0; + +Benchmark::Benchmark() : UnitTest() { + time=0; + runs=0; +} + +void Benchmark::Start(uString Text,...){ + // Rebuild input string + va_list arg; + va_start(arg,Text); + Text=RebuildString(Text,arg); + va_end(arg); + LogRaw(LLMESSAGE,"| %-50s",Text.c_str()); + + // Register start + start=SDL_GetTicks(); +} + +Uint32 Benchmark::Stop(int Runs){ + Uint32 delta=SDL_GetTicks()-start; + LogRaw(LLMESSAGE,"% 8dmS % 8dmS |\r\n",delta,delta/Runs); + total_time+=delta; + total_runs+=Runs; + time+=delta; + runs+=Runs; + return delta; +} + +void Benchmark::Summary(){ +} + +void Benchmark::Report(){ + if(runs){ + uString dash; + for(int i=0;i<76;i++) dash+="-"; + LogMessage(dash); + Uint32 old_time=total_time; + Uint32 old_runs=total_runs; + Start("Runtime statistics"); + start=start-time; + Stop(runs); + total_time=old_time; + total_runs=old_runs; + time=0; + runs=0; + LogMessage(dash); + } +} + diff --git a/engines/vileVN/testing/benchmark.h b/engines/vileVN/testing/benchmark.h new file mode 100644 index 0000000000..fd1e3fa8a3 --- /dev/null +++ b/engines/vileVN/testing/benchmark.h @@ -0,0 +1,27 @@ +#ifndef _BENCHMARK_H_ +#define _BENCHMARK_H_ + +#include "utest.h" + +class Benchmark : public UnitTest { + private: + static Uint32 total_time; + static Uint32 total_runs; + Uint32 time; + Uint32 runs; + Uint32 start; + protected: + // Only derived objects please ... + Benchmark(); + + // Benchmarking API + void Start(uString Text,...); + Uint32 Stop(int Runs); + void Report(); + public: + static void Summary(); + +}; + +#endif + diff --git a/engines/vileVN/testing/coretest.cpp b/engines/vileVN/testing/coretest.cpp new file mode 100644 index 0000000000..8964ae9241 --- /dev/null +++ b/engines/vileVN/testing/coretest.cpp @@ -0,0 +1,199 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "coretest.h" + +CoreTest::CoreTest(){ + // Test stringlist objects + Header("Core macros"); + Assert(EDL_ABS(-1)==1,"ABS gives absolute on negative integers"); + Assert(EDL_ABS(1)==1,"ABS gives absolute on positive integers"); + Assert(EDL_ABS(0)==0,"ABS gives null on null integer"); + Assert(EDL_ABS((double)-1)==1,"ABS gives absolute on negative floats"); + Assert(EDL_ABS((double)1)==1,"ABS gives absolute on positive floats"); + Assert(EDL_ABS((double)0)==0,"ABS gives null on null float"); + Assert(EDL_MAX(0,1)==1,"MAX picks largest positive number"); + Assert(EDL_MAX(1,1)==1,"MAX picks among equals"); + Assert(EDL_MAX(1,-1)==1,"MAX picks positives over negatives"); + Assert(EDL_MAX(0,-1)==0,"MAX picks null over negatives"); + Assert(EDL_MIN(0,1)==0,"MIN picks smallest positive number"); + Assert(EDL_MIN(1,1)==1,"MIN picks among equals"); + Assert(EDL_MIN(1,-1)==-1,"MIN picks negatives over posives"); + Assert(EDL_MIN(0,-1)==-1,"MAX picks negatives over null"); + Assert(EDL_LIMIT(0,1,2)==1,"LIMIT floors values correctly"); + Assert(EDL_LIMIT(3,1,2)==2,"LIMIT limits values correctly"); + Assert(EDL_LIMIT(1,1,2)==1,"LIMIT accepts lower limit"); + Assert(EDL_LIMIT(2,1,2)==2,"LIMIT accepts upper limit"); + Assert(EDL_LIMIT(2,1,3)==2,"LIMIT accepts range"); + + Header("Random number generator"); + int nulls=0; + int ones=0; + int max=0; + int min=2; + for(int i=0;i<1000;i++){ + int seed=EDL_Random(0,1); + if(seed>max){ + max=seed; + } + if(seed=0,"Lower range is honoured when really narrow"); + Assert(nulls+ones==1000,"Correct number of narrowly ranged hits"); + Assert(nulls>100,"A reasonable number if nulls on narrow range"); + Assert(ones>100,"A reasonable number if ones on narrow range"); + nulls=0; + ones=0; + max=0; + min=1001; + for(int i=0;i<1000;i++){ + int seed=EDL_Random(0,1000); + if(seed>max){ + max=seed; + } + if(seed=0&&seed<=1000){ + ones++; + } + if(seed>=0&&seed<=500){ + nulls++; + } + + } + Assert(max<1001,"Upper range is honoured when wide"); + Assert(min>=0,"Lower range is honoured when wide"); + Assert(ones==1000,"Correct number of widely ranged hits"); + Assert(nulls>100,"A reasonable number of lows on narrow range"); + Assert(nulls<900,"A reasonable number of highs on narrow range"); + + + Header("Core Objects"); + Stringlist sl1; + Assert(sl1.GetCount()==0,"New stringlist objects are empty"); + sl1.SetString(0,"1"); + Assert(sl1.GetCount()==1,"Adding null indexed data gives single string"); + sl1.SetString(0,"1"); + Assert(sl1.GetCount()==1,"Changing null indexed data does not add data"); + for(int i=1;i<1000;i++){ + sl1.SetString(i,"Text"); + } + Assert(sl1.GetCount()==1000,"Stringlist handles 1000 items unprepared"); + Stringlist sl2(1000); + Assert(sl2.GetCount()==1000,"Stringlist can preload 1000 items"); + for(int i=0;i<1000;i++){ + sl2.SetString(i,"Text"); + } + Assert(sl2.GetCount()==1000,"Preloaded items can be modified"); + uString s; + Assert(sl2.GetString(500,&s),"Strings can be loaded"); + Assert(s=="Text","Loaded strings export as expected"); + Stringlist sl3(sl2); + Assert(sl3.GetCount()==1000,"Copyconstructor copies loaded strings"); + Assert(sl3.GetString(500,&s),"Constructor-copied strings can be loaded"); + Assert(s=="Text","Contructor-copied strings export as expected"); + Stringlist sl4; + Stringlist sl5; + Assert(sl4.GetCount()==0,"New stringlist objects are still empty"); + sl4=sl3; + Assert(sl4.GetCount()==1000,"Stringlists copy operator works"); + sl4=sl5; + Assert(sl4.GetCount()==0,"Stringlists copy operator takes empty lists"); + Assert(!sl4.GetString(500,&s),"Empty strings not available"); + Assert(sl3.GetCount()==1000,"Original list maintains own copy"); + Assert(sl3.GetString(500,&s),"Original strings can be loaded"); + Assert(s=="Text","Original strings export as expected"); + + // Vector objects + DVector v1; + Assert(v1.GetUint32(0)==0,"Empty Uint32 vector items returns null"); + Assert(v1.GetUint16(0)==0,"Empty Uint16 vector items returns null"); + Assert(v1.GetUint8(0)==0,"Empty Uint8 vector items returns null"); + Assert(v1.GetSint32(0)==0,"Empty Sint32 vector items returns null"); + Assert(v1.GetSint16(0)==0,"Empty Sint16 vector items returns null"); + Assert(v1.GetSint8(0)==0,"Empty Sint8 vector items returns null"); + v1.SetUint32(0,1); + Assert(v1.GetUint32(0)==1,"Uint32 vector items register"); + v1.SetUint16(0,2); + Assert(v1.GetUint16(0)==2,"Uint16 vector items register"); + v1.SetUint8(0,3); + Assert(v1.GetUint8(0)==3,"Uint8 vector items register"); + v1.SetSint32(0,-1); + Assert(v1.GetSint32(0)==-1,"Sint32 vector items register"); + v1.SetSint16(0,-2000); + Assert(v1.GetSint16(0)==-2000,"Sint16 vector items register"); + v1.SetSint32(0,10); + Assert(v1.GetSint8(0)==10,"Sint8 vector items register"); + for(int i=0;i<1000;i++){ + v1.SetUint32(i,i); + } + Assert(v1.GetUint32(999)==999,"Vector handles 1000 items unprepared"); + bool test=true; + for(unsigned int i=0;i<1000;i++){ + test&=v1.GetUint32(i)==i; + } + Assert(test,"Vector items readtest without preloading"); + DVector v2(1000); + for(int i=0;i<1000;i++){ + v2.SetUint32(i,i); + } + Assert(v2.GetUint32(999)==999,"Vector handles 1000 items prepared"); + test=true; + for(unsigned int i=0;i<1000;i++){ + test&=v2.GetUint32(i)==i; + } + Assert(test,"Vector items readtest with preloading"); + DVector v3=v2; + Assert(v3.GetUint32(999)==999,"Vector copy operator handles 1000 items"); + test=true; + for(unsigned int i=0;i<1000;i++){ + test&=v3.GetUint32(i)==i; + } + Assert(test,"Vector items readtest for copied items"); + + // Test stack objects + DStack s1; + Assert(s1.Count()==0,"New stack objects are empty"); + Assert(s1.Pop()==0,"Empty stack objects cant pop"); + Assert(s1.Peek()==0,"Empty stack objects cant peek"); + Assert(s1.Drop(0)==0,"Empty stack objects cant drop"); + Assert(s1.Get(0)==0,"Empty stack objects dont have null indexed item"); + Assert(s1.Get(100)==0,"Empty stack objects dont have items"); + int i1=99; + s1.Queue(&i1); + Assert(s1.Get(0)==&i1,"Empty stack objects can queue items"); + Assert(s1.Get(0)==&i1,"Read items are not popped"); + Assert(s1.Pop()==&i1,"Queued items can be popped"); + Assert(s1.Get(0)==0,"Popped items dissapears"); + s1.Push(&i1); + Assert(s1.Get(0)==&i1,"Empty stack objects can push items"); + Assert(s1.Peek()==&i1,"Pushed items can be peeked"); + Assert(s1.Peek()==&i1,"Peeked objects remains on the stack"); + Assert(s1.Pop()==&i1,"Pushed items can be popped"); + Assert(s1.Get(0)==0,"Popped items dissapears"); + + // Sum up + Report(); +} diff --git a/engines/vileVN/testing/coretest.h b/engines/vileVN/testing/coretest.h new file mode 100644 index 0000000000..e1ba43beef --- /dev/null +++ b/engines/vileVN/testing/coretest.h @@ -0,0 +1,12 @@ +#ifndef _CORETEST_H_ +#define _CORETEST_H_ + +#include "utest.h" + +class CoreTest : public UnitTest { + public: + CoreTest(); +}; + +#endif + diff --git a/engines/vileVN/testing/filetest.cpp b/engines/vileVN/testing/filetest.cpp new file mode 100644 index 0000000000..e34c1fad3b --- /dev/null +++ b/engines/vileVN/testing/filetest.cpp @@ -0,0 +1,438 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "filetest.h" + +FileTest::FileTest(){ + // Test archive handling + Header("Archive Handling"); + ArchiveItem ai1("dir/file",0,0,0); + Assert(ai1.dir=="dir/","Parsing directory \"dir/file\" -> \"dir/\""); + Assert(ai1.base=="file","Parsing basename \"dir/file\" -> \"file\""); + Assert(ai1.ext=="","Parsing extension \"dir/file\" -> \"\""); + ai1.Set("/dir/file",0,0,0); + Assert(ai1.dir=="/dir/","Parsing directory \"/dir/file\" -> \"/dir/\""); + Assert(ai1.base=="file","Parsing basename \"/dir/file\" -> \"file\""); + Assert(ai1.ext=="","Parsing extension \"/dir/file\" -> \"\""); + ai1.Set("file",0,0,0); + Assert(ai1.dir=="","Parsing directory \"file\" -> \"\""); + Assert(ai1.base=="file","Parsing basename \"file\" -> \"file\""); + Assert(ai1.ext=="","Parsing extension \"file\" -> \"\""); + ai1.Set("file.ext",0,0,0); + Assert(ai1.dir=="","Parsing directory \"file.ext\" -> \"\""); + Assert(ai1.base=="file","Parsing basename \"file.ext\" -> \"file\""); + Assert(ai1.ext=="ext","Parsing extension \"file.ext\" -> \"ext\""); + ai1.Set("dir/file.ext",0,0,0); + Assert(ai1.dir=="dir/","Parsing directory \"dir/file.ext\" -> \"dir/\""); + Assert(ai1.base=="file","Parsing basename \"dir/file.ext\" -> \"file\""); + Assert(ai1.ext=="ext","Parsing extension \"dir/file.ext\" -> \"ext\""); + + // Test red-black search tree + RedBlackTree tree(new ArchiveNil,new ArchiveRoot); + Assert(tree.Count()==0,"Default red-black tree is empty"); + char buffer[12]; + for(int i=0;i<1000;i++){ + sprintf(buffer,"%d.%d",i,i); + tree.Insert(new ArchiveItem(buffer,i,i,i),SORT_STRICT); + } + Assert(tree.Count()==1000,"Red-black tree accepted 1000 items"); + ai1.Set("530",0,0,0); + ArchiveItem *ai2=(ArchiveItem*)tree.Search(&ai1,SORT_STRICT); + Assert(ai2==0,"Red-black strict search filtered missing extension"); + ai2=(ArchiveItem*)tree.Search(&ai1,SORT_NOEXT); + Assert(ai2,"Red-black noext search ignored missing extension"); + Assert(ai2 && ai2->dsize==530,"Red-black search retrieved correct size"); + Assert(ai2 && ai2->offset==530,"Red-black search retrieved correct offset"); + ai1.ext="530"; + ai2=(ArchiveItem*)tree.Search(&ai1,SORT_STRICT); + Assert(ai2,"Red-black strict search accepted extension"); + Assert(ai2 && ai2->dsize==530,"Red-black search retrieved correct size"); + Assert(ai2 && ai2->offset==530,"Red-black search retrieved correct offset"); + ai2=(ArchiveItem*)tree.Search(&ai1,SORT_NOEXT); + Assert(ai2,"Red-black noext search accepted extension"); + Assert(ai2 && ai2->dsize==530,"Red-black search retrieved correct size"); + Assert(ai2 && ai2->offset==530,"Red-black search retrieved correct offset"); + ai1.ext="0"; + ai2=(ArchiveItem*)tree.Search(&ai1,SORT_STRICT); + Assert(ai2==0,"Red-black strict search filtered bad extension"); + ai2=(ArchiveItem*)tree.Search(&ai1,SORT_NOEXT); + Assert(ai2,"Red-black noext search ignored bad extension"); + Assert(ai2 && ai2->dsize==530,"Red-black search retrieved correct size"); + Assert(ai2 && ai2->offset==530,"Red-black search retrieved correct offset"); + + // Cumulative search tests + bool test=true; + for(int i=0;i<1000;i++){ + sprintf(buffer,"%d.%d",i,i); + ai1.Set(buffer,0,0,0); + test&=tree.Search(&ai1,SORT_STRICT)!=0; + } + Assert(test,"Red-black successive search test"); + test=true; + for(int i=999;i>=0;i--){ + sprintf(buffer,"%d.%d",i,i); + ai1.Set(buffer,0,0,0); + test&=tree.Search(&ai1,SORT_STRICT)!=0; + } + Assert(test,"Reverse red-black successive search test"); + test=true; + srand(time(NULL)); + for(int i=0;i<1000;i++){ + int j=rand()%1000; + sprintf(buffer,"%d.%d",j,j); + ai1.Set(buffer,0,0,0); + test&=tree.Search(&ai1,SORT_STRICT)!=0; + } + Assert(test,"Red-black random order search test"); + + + Header("Filename Handling"); + // Path directory + uString i="/home/me/isafile"; + uString o="/home/me/"; + uString r=EDL_FileDirectory(i); + + Assert(r==o,"EDL_FileDirectory(%s) = %s",i.c_str(),r.c_str()); + i="/home/me/isafile.ext"; + o="/home/me/"; + r=EDL_FileDirectory(i); + Assert(r==o,"EDL_FileDirectory(%s) = %s",i.c_str(),o.c_str()); + i="me/dir/"; + o="me/dir/"; + r=EDL_FileDirectory(i); + Assert(r==o,"EDL_FileDirectory(%s) = %s",i.c_str(),o.c_str()); + i="me/thisisafile"; + o="me/"; + r=EDL_FileDirectory(i); + Assert(r==o,"EDL_FileDirectory(%s) = %s",i.c_str(),o.c_str()); + + // File basename + i="/home/me/isafile"; + o="isafile"; + r=EDL_Searchname(i); + Assert(r==o,"EDL_Searchname(%s) = %s",i.c_str(),o.c_str()); + i="/home/me/ISAfilE.eXt"; + o="isafile"; + r=EDL_Searchname(i); + Assert(r==o,"EDL_Searchname(%s) = %s",i.c_str(),o.c_str()); + i="/home/me/isafile"; + o="isafile"; + r=EDL_FileName(i); + Assert(r==o,"EDL_FileName(%s) = %s",i.c_str(),o.c_str()); + i="/home/me/isafile.ext"; + o="isafile"; + r=EDL_FileName(i); + Assert(r==o,"EDL_FileName(%s) = %s",i.c_str(),o.c_str()); + i="/home/"; + o=""; + r=EDL_FileName(i); + Assert(r==o,"EDL_FileName(%s) = %s",i.c_str(),o.c_str()); + i="me/dir/"; + o=""; + r=EDL_FileName(i); + Assert(r==o,"EDL_FileName(%s) = %s",i.c_str(),o.c_str()); + i="me/thisisafile"; + o="thisisafile"; + r=EDL_FileName(i); + Assert(r==o,"EDL_FileName(%s) = %s",i.c_str(),o.c_str()); + i="me/thisisafile."; + o="thisisafile"; + r=EDL_FileName(i); + Assert(r==o,"EDL_FileName(%s) = %s",i.c_str(),o.c_str()); + + // File extension + i="me/afile"; + o="me/afile.ext"; + r=EDL_DefaultExtension(i,"ext"); + Assert(r==o,"EDL_DefaultExtension(%s) = %s",i.c_str(),o.c_str()); + i="me/afile.ext"; + o="me/afile.ext"; + r=EDL_DefaultExtension(i,"txt"); + Assert(r==o,"EDL_DefaultExtension(%s) = %s",i.c_str(),o.c_str()); + i="me/afile"; + o="me/afile.ext"; + r=EDL_ForceExtension(i,"ext"); + Assert(r==o,"EDL_ForceExtension(%s) = %s",i.c_str(),o.c_str()); + i="me/afile.ext"; + o="me/afile.txt"; + r=EDL_ForceExtension(i,"txt"); + Assert(r==o,"EDL_ForceExtension(%s) = %s",i.c_str(),o.c_str()); + i="/home/me/isafile"; + o=""; + r=EDL_FileExtension(i); + Assert(r==o,"EDL_FileExtension(%s) = %s",i.c_str(),o.c_str()); + i="/home/me/isafile.ext"; + o="ext"; + r=EDL_FileExtension(i); + Assert(r==o,"EDL_FileExtension(%s) = %s",i.c_str(),o.c_str()); + i="/home/"; + o=""; + r=EDL_FileExtension(i); + Assert(r==o,"EDL_FileExtension(%s) = %s",i.c_str(),o.c_str()); + i="me/dir/"; + o=""; + r=EDL_FileExtension(i); + Assert(r==o,"EDL_FileExtension(%s) = %s",i.c_str(),o.c_str()); + i="me/thisisafile"; + o=""; + r=EDL_FileExtension(i); + Assert(r==o,"EDL_FileExtension(%s) = %s",i.c_str(),o.c_str()); + i="me/thisisafile."; + o=""; + r=EDL_FileExtension(i); + Assert(r==o,"EDL_FileExtension(%s) = %s",i.c_str(),o.c_str()); + i="me/afile.extension"; + o="extension"; + r=EDL_FileExtension(i); + Assert(r==o,"EDL_FileExtension(%s) = %s",i.c_str(),o.c_str()); + +#ifdef VILE_ARCH_MICROSOFT + // Path directory + i="C:\\home\\me\\isafile"; + o="C:\\home\\me\\"; + r=EDL_FileDirectory(i); + Assert(r==o,"EDL_FileDirectory(%s) = %s",i.c_str(),o.c_str()); + i="C:\\home\\me\\isafile.ext"; + o="C:\\home\\me\\"; + r=EDL_FileDirectory(i); + Assert(r==o,"EDL_FileDirectory(%s) = %s",i.c_str(),o.c_str()); + i="C:\\"; + o="C:\\"; + r=EDL_FileDirectory(i); + Assert(r==o,"EDL_FileDirectory(%s) = %s",i.c_str(),o.c_str()); + i="me\\dir\\"; + o="me\\dir\\"; + r=EDL_FileDirectory(i); + Assert(r==o,"EDL_FileDirectory(%s) = %s",i.c_str(),o.c_str()); + i="me\\thisisafile"; + o="me\\"; + r=EDL_FileDirectory(i); + Assert(r==o,"EDL_FileDirectory(%s) = %s",i.c_str(),o.c_str()); + + // File basename + i="C:\\home\\me\\isafile"; + o="isafile"; + r=EDL_Searchname(i); + Assert(r==o,"EDL_Searchname(%s) = %s",i.c_str(),o.c_str()); + i="C:\\home\\me\\ISAfilE.eXt"; + o="isafile"; + r=EDL_Searchname(i); + Assert(r==o,"EDL_Searchname(%s) = %s",i.c_str(),o.c_str()); + i="C:\\home\\me\\isafile"; + o="isafile"; + r=EDL_FileName(i); + Assert(r==o,"EDL_FileName(%s) = %s",i.c_str(),o.c_str()); + i="C:\\home\\me\\isafile.ext"; + o="isafile"; + r=EDL_FileName(i); + Assert(r==o,"EDL_FileName(%s) = %s",i.c_str(),o.c_str()); + i="C:\\"; + o=""; + r=EDL_FileName(i); + Assert(r==o,"EDL_FileName(%s) = %s",i.c_str(),o.c_str()); + i="me\\dir\\"; + o=""; + r=EDL_FileName(i); + Assert(r==o,"EDL_FileName(%s) = %s",i.c_str(),o.c_str()); + i="me\\thisisafile"; + o="thisisafile"; + r=EDL_FileName(i); + Assert(r==o,"EDL_FileName(%s) = %s",i.c_str(),o.c_str()); + i="me\\thisisafile."; + o="thisisafile"; + r=EDL_FileName(i); + Assert(r==o,"EDL_FileName(%s) = %s",i.c_str(),o.c_str()); + + // File extension + i="me\\afile"; + o="me\\afile.ext"; + r=EDL_DefaultExtension(i,"ext"); + Assert(r==o,"EDL_DefaultExtension(%s) = %s",i.c_str(),o.c_str()); + i="me\\afile.ext"; + o="me\\afile.ext"; + r=EDL_DefaultExtension(i,"txt"); + Assert(r==o,"EDL_DefaultExtension(%s) = %s",i.c_str(),o.c_str()); + i="me\\afile"; + o="me\\afile.ext"; + r=EDL_ForceExtension(i,"ext"); + Assert(r==o,"EDL_ForceExtension(%s) = %s",i.c_str(),o.c_str()); + i="me\\afile.ext"; + o="me\\afile.txt"; + r=EDL_ForceExtension(i,"txt"); + Assert(r==o,"EDL_ForceExtension(%s) = %s",i.c_str(),o.c_str()); + i="X:\\home\\me\\isafile"; + o=""; + r=EDL_FileExtension(i); + Assert(r==o,"EDL_FileExtension(%s) = %s",i.c_str(),o.c_str()); + i="X:\\home\\me\\isafile.ext"; + o="ext"; + r=EDL_FileExtension(i); + Assert(r==o,"EDL_FileExtension(%s) = %s",i.c_str(),o.c_str()); + i="C:\\"; + o=""; + r=EDL_FileExtension(i); + Assert(r==o,"EDL_FileExtension(%s) = %s",i.c_str(),o.c_str()); + i="me\\dir\\"; + o=""; + r=EDL_FileExtension(i); + Assert(r==o,"EDL_FileExtension(%s) = %s",i.c_str(),o.c_str()); + i="me\\thisisafile"; + o=""; + r=EDL_FileExtension(i); + Assert(r==o,"EDL_FileExtension(%s) = %s",i.c_str(),o.c_str()); + i="me\\thisisafile."; + o=""; + r=EDL_FileExtension(i); + Assert(r==o,"EDL_FileExtension(%s) = %s",i.c_str(),o.c_str()); + i="me\\afile.extension"; + o="extension"; + r=EDL_FileExtension(i); + Assert(r==o,"EDL_FileExtension(%s) = %s",i.c_str(),o.c_str()); +#endif + + Header("Filesystem access"); + test=EDL_ReadableDirectory("asdjfasdfasfladsn32sssnk"); + Assert(!test,"EDL_ReadableDirectory refuses junk name"); + test=EDL_WritableDirectory("asd24r24rn4r2nkjjfasnk"); + Assert(!test,"EDL_WritableDirectory refuses junk name"); + test=EDL_ReadableFile("asdjfasdfasfladsn32sssnk"); + Assert(!test,"EDL_ReadableFile refuses junk name"); + test=EDL_WritableFile("asd24r24rn4r2nkjjfasnk"); + Assert(!test,"EDL_WritableFile refuses junk name"); + test=EDL_ReadableFile("asdjfasdfasfladsn32sssnk/dasda"); + Assert(!test,"EDL_ReadableFile refuses nested junk name"); + test=EDL_WritableFile("asd24r24rn4r2nkjjfasnk/dasdas"); + Assert(!test,"EDL_WritableFile refuses nested junk name"); + uString dir=EDL_CreateTemporary(); + Assert(dir.length(),"Can create temporary directory",dir.c_str()); + test=EDL_ReadableDirectory(dir); + Assert(test,"EDL_ReadableDirectory accepted temporary"); + test=EDL_WritableDirectory (dir); + Assert(test,"EDL_WritableDirectory accepted temporary"); + test=EDL_ReadableFile(dir); + Assert(!test,"EDL_ReadableFile refused temporary directory"); + test=EDL_WritableFile(dir); + Assert(!test,"EDL_WritableFile refused temporary directory"); + test=EDL_DeleteDirectory(dir); + Assert(test,"Can delete empty directories"); + test=EDL_ReadableDirectory(dir); + Assert(!test,"EDL_ReadableDirectory verified deletion"); + test=EDL_WritableDirectory (dir); + Assert(!test,"EDL_WritableDirectory verified deletion"); + + Header("Configuration files"); + uString cfgd=EDL_CreateTemporary(); + uString cfgf=cfgd+"unittest.ini"; + uString t_string; + double t_double; + int t_int; + INIFile ini1(true); + test=ini1.Get("Section","String",t_string); + Assert(!test,"Empty inifile refuses string requests"); + test=ini1.Get("Section","Double",t_double); + Assert(!test,"Empty inifile refuses double requests"); + test=ini1.Get("Section","Integer",t_int); + Assert(!test,"Empty inifile refuses integer requests"); + test=ini1.Set("Section","Key","Value1"); + Assert(test,"Inifile accepts string values"); + test=ini1.Get("Section","Key",t_string); + Assert(test,"Non-empty inifile accepts string requests"); + Assert(t_string=="Value1","Inifile returns original string"); + test=ini1.Set("Section","Key","Value1"); + Assert(test,"Inifile accepts identical string values"); + test=ini1.Get("Section","Key",t_string); + Assert(test,"Non-empty inifile still accepts string requests"); + Assert(t_string=="Value1","Inifile returns rewritten string"); + test=ini1.Set("Section","Key","Value2"); + Assert(test,"Inifile accepts different string values"); + test=ini1.Get("Section","Key",t_string); + Assert(test,"Non-empty inifile still accepts string requests"); + Assert(t_string=="Value2","Inifile returns overwritten string"); + test=ini1.Set("Section","NewKey","Value"); + Assert(test,"Inifile accepts writing values to other keys"); + test=ini1.Get("Section","Key",t_string); + Assert(test,"Non-empty inifile still accepts string requests"); + Assert(t_string=="Value2","Inifile retains key when writing to others"); + test=ini1.Set("Section","String","string"); + Assert(test,"inifile accept string value"); + test=ini1.Set("Section","Double",1.23); + Assert(test,"inifile accept double value"); + test=ini1.Set("Section","Integer",10); + Assert(test,"inifile accepts integer values"); + test=ini1.Get("Section","String",t_string); + Assert(test,"Inifile copy responds to valid string requests"); + Assert(t_string=="string","Copied inifile string values are correct"); + test=ini1.Get("Section","Double",t_double); + Assert(test,"Inifile copy responds to valid double requests"); + Assert(t_double==1.23,"Copied inifile double values are correct"); + test=ini1.Get("Section","Integer",t_int); + Assert(test,"Inifile copy responds to valid integer requests"); + Assert(t_int==10,"Copied inifile double values are correct"); + test=ini1.Get("Section","string",t_string); + Assert(!test,"Inifiles honors case sensitivity on string requests"); + test=ini1.Get("Section","double",t_double); + Assert(!test,"Inifiles honors case sensitivity on double requests"); + test=ini1.Get("Section","integer",t_int); + Assert(!test,"Inifiles honors case sensitivity on integer requests"); + test=ini1.Get("section","String",t_string); + Assert(!test,"Inifiles honors case sensitivity on string requests"); + test=ini1.Get("section","Double",t_double); + Assert(!test,"Inifiles honors case sensitivity on double requests"); + test=ini1.Get("section","Integer",t_int); + Assert(!test,"Inifiles honors case sensitivity on integer requests"); + Assert(ini1.WriteFile(cfgf),"Inifiles writes to disk"); + + // Now open existing inifile + INIFile ini2(false); + Assert(ini2.ReadFile(cfgf),"Inifiles reads from disk"); + test=ini2.Get("Section","String",t_string); + Assert(test,"Inifile copy responds to valid string requests"); + Assert(t_string=="string","Copied inifile string values are correct"); + test=ini2.Get("Section","Double",t_double); + Assert(test,"Inifile copy responds to valid double requests"); + Assert(t_double==1.23,"Copied inifile double values are correct"); + test=ini2.Get("Section","Integer",t_int); + Assert(test,"Inifile copy responds to valid integer requests"); + Assert(t_int==10,"Copied inifile double values are correct"); + test=ini2.Get("Section","string",t_string); + Assert(test,"Inifiles honors case insensitivity on string requests"); + test=ini2.Get("Section","double",t_double); + Assert(test,"Inifiles honors case insensitivity on double requests"); + test=ini2.Get("Section","integer",t_int); + Assert(test,"Inifiles honors case insensitivity on int requests"); + test=ini2.Get("section","string",t_string); + Assert(test,"Inifiles honors case insensitivity on string requests"); + test=ini2.Get("section","double",t_double); + Assert(test,"Inifiles honors case insensitivity on double requests"); + test=ini2.Get("section","integer",t_int); + Assert(test,"Inifiles honors case insensitivity on int requests"); + + // Clean up + test=EDL_DeleteDirectory(cfgd); + Assert(test,"Can delete populated directories"); + test=EDL_ReadableFile(cfgf); + Assert(!test,"EDL_ReadableFile verified deletion"); + test=EDL_WritableFile(cfgf); + Assert(!test,"EDL_WritableFile verified deletion"); + test=EDL_ReadableDirectory(cfgd); + Assert(!test,"EDL_ReadableDirectory verified deletion"); + test=EDL_WritableDirectory (cfgd); + Assert(!test,"EDL_WritableDirectory verified deletion"); + + + // Sum up + Report(); +} + diff --git a/engines/vileVN/testing/filetest.h b/engines/vileVN/testing/filetest.h new file mode 100644 index 0000000000..45df028516 --- /dev/null +++ b/engines/vileVN/testing/filetest.h @@ -0,0 +1,12 @@ +#ifndef _FILETEST_H_ +#define _FILETEST_H_ + +#include "utest.h" + +class FileTest : public UnitTest { + public: + FileTest(); +}; + +#endif + diff --git a/engines/vileVN/testing/gfxbench.cpp b/engines/vileVN/testing/gfxbench.cpp new file mode 100644 index 0000000000..b5ebb0b019 --- /dev/null +++ b/engines/vileVN/testing/gfxbench.cpp @@ -0,0 +1,69 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "gfxbench.h" + +GFXBench::GFXBench(int Runs){ + Header("Graphic functions"); + SDL_Surface *s1=EDL_CreateSurface(640,480); + SDL_Surface *s2=EDL_CreateSurface(640,480); + Start("Creating and deallocating %d 640x480 surfaces",Runs); + for(int i=0;i0,"ANSI string reference test II"); + Assert(a1.compare("test")<0,"ANSI string reference test III"); + Assert(a1.compare("t")<0,"ANSI string reference test IV"); + Assert(a1.compare("Testx")<0,"ANSI string reference test V"); + Assert(a1.compare("testx")<0,"ANSI string reference test VI"); + Assert(a1.compare("T")>0,"ANSI string reference test VII"); + Assert(a1.compare("Tes")>0,"ANSI string reference test VIII"); + Assert(a1.compare(" ")>0,"ANSI string reference test IX"); + Assert(a1.compare("5")>0,"ANSI string reference test X"); + Assert(a2.compare("")==0,"ANSI string reference test XI"); + Assert(a2.compare("Test")<0,"ANSI string reference test XII"); + Assert(a2.compare("t")<0,"ANSI string reference test XIII"); + Assert(a2.compare(" ")<0,"ANSI string reference test XIV"); + Assert(a2.compare("1")<0,"ANSI string reference test XV"); + Assert(a2.compare("testx")<0,"ANSI string reference test XVI"); + Assert(a2.compare("T")<0,"ANSI string reference test XVII"); + Assert(a2.compare("Tes")<0,"ANSI string reference test XVIII"); + +#ifdef VILE_BUILD_UNICODE + wString w1=L"Test"; + wString w2=L""; + Assert(w1.compare(L"Test")==0,"Wide string reference test I"); + Assert(w1.compare(L"")>0,"Wide string reference test II"); + Assert(w1.compare(L"test")<0,"Wide string reference test III"); + Assert(w1.compare(L"t")<0,"Wide string reference test IV"); + Assert(w1.compare(L"Testx")<0,"Wide string reference test V"); + Assert(w1.compare(L"testx")<0,"Wide string reference test VI"); + Assert(w1.compare(L"T")>0,"Wide string reference test VII"); + Assert(w1.compare(L"Tes")>0,"Wide string reference test VIII"); + Assert(w1.compare(L" ")>0,"Wide string reference test IX"); + Assert(w1.compare(L"5")>0,"Wide string reference test X"); + Assert(w2.compare(L"")==0,"Wide string reference test XI"); + Assert(w2.compare(L"Test")<0,"Wide string reference test XII"); + Assert(w2.compare(L"t")<0,"Wide string reference test XIII"); + Assert(w2.compare(L" ")<0,"Wide string reference test XIV"); + Assert(w2.compare(L"1")<0,"Wide string reference test XV"); + Assert(w2.compare(L"testx")<0,"Wide string reference test XVI"); + Assert(w2.compare(L"T")<0,"Wide string reference test XVII"); + Assert(w2.compare(L"Tes")<0,"Wide string reference test XVIII"); + + uString u1="Test"; + uString u2=""; + Assert(u1.compare(L"Test")==0,"String reference test I"); + Assert(u1.compare(L"")>0,"String reference test II"); + Assert(u1.compare(L"test")<0,"String reference test III"); + Assert(u1.compare(L"t")<0,"String reference test IV"); + Assert(u1.compare(L"Testx")<0,"String reference test V"); + Assert(u1.compare(L"testx")<0,"String reference test VI"); + Assert(u1.compare(L"T")>0,"String reference test VII"); + Assert(u1.compare(L"Tes")>0,"String reference test VIII"); + Assert(u1.compare(L" ")>0,"String reference test IX"); + Assert(u1.compare(L"5")>0,"String reference test X"); + Assert(u2.compare(L"")==0,"String reference test XI"); + Assert(u2.compare(L"Test")<0,"String reference test XII"); + Assert(u2.compare(L"t")<0,"String reference test XIII"); + Assert(u2.compare(L" ")<0,"String reference test XIV"); + Assert(u2.compare(L"1")<0,"String reference test XV"); + Assert(u2.compare(L"testx")<0,"String reference test XVI"); + Assert(u2.compare(L"T")<0,"String reference test XVII"); + Assert(u2.compare(L"Tes")<0,"String reference test XVIII"); + u1=L"Test"; + u2=L""; + Assert(u1.compare(L"Test")==0,"String reference test I"); + Assert(u1.compare(L"")>0,"String reference test II"); + Assert(u1.compare(L"test")<0,"String reference test III"); + Assert(u1.compare(L"t")<0,"String reference test IV"); + Assert(u1.compare(L"Testx")<0,"String reference test V"); + Assert(u1.compare(L"testx")<0,"String reference test VI"); + Assert(u1.compare(L"T")>0,"String reference test VII"); + Assert(u1.compare(L"Tes")>0,"String reference test VIII"); + Assert(u1.compare(L" ")>0,"String reference test IX"); + Assert(u1.compare(L"5")>0,"String reference test X"); + Assert(u2.compare(L"")==0,"String reference test XI"); + Assert(u2.compare(L"Test")<0,"String reference test XII"); + Assert(u2.compare(L"t")<0,"String reference test XIII"); + Assert(u2.compare(L" ")<0,"String reference test XIV"); + Assert(u2.compare(L"1")<0,"String reference test XV"); + Assert(u2.compare(L"testx")<0,"String reference test XVI"); + Assert(u2.compare(L"T")<0,"String reference test XVII"); + Assert(u2.compare(L"Tes")<0,"String reference test XVIII"); +#endif + + // Constructor sanitation tests + uString u("Test"); + Assert(u.substr(1,2)=="es","std::substr compliancy"); + Assert(u.substr(0)=="Test","std::substr compliancy"); + Assert(u.substr(0,5)=="Test","std::substr compliancy"); + Assert(u.substr(0,4)=="Test","std::substr compliancy"); + Assert(u.substr(0,1)=="T","std::substr compliancy"); + Assert(u.substr(1,1)=="e","std::substr compliancy"); + Assert(u.substr(1,0)=="","std::substr compliancy"); + Assert(u.substr(1)=="est","std::substr compliancy"); + Assert(u.substr(4)=="","std::substr compliancy"); + Assert(uString("Test")=="Test","String constructor test I"); + Assert(uString("Test")!="test","String constructor test II"); +#ifdef VILE_BUILD_UNICODE + Assert(uString(L"Test")=="Test","String constructor test III"); + Assert(uString("Test")==L"Test","String constructor test IV"); + Assert(uString('T')=="T","String constructor test V"); + Assert(uString(L'T')=="T","String constructor test VI"); + Assert(uString('T')==L"T","String constructor test VII"); + Assert(uString("Test").bytes()==4,"String constructor test VIII"); + Assert(uString(L"Test").bytes()==4,"String constructor test IX"); + Assert(uString('T').bytes()==1,"String constructor test X"); + Assert(uString(L'T').bytes()==1,"String constructor test XI"); + Assert(uString('T').bytes()==1,"String constructor test XII"); + Assert(uString("Test").points()==4,"String constructor test XIII"); + Assert(uString(L"Test").points()==4,"String constructor test XIV"); + Assert(uString('T').points()==1,"String constructor test XV"); + Assert(uString(L'T').points()==1,"String constructor test XVI"); + Assert(uString('T').points()==1,"String constructor test XVII"); + Assert(uString(L"10").to_int()==10,"Wide strings converts integers"); + Assert(uString(L"10").to_int(16)==16,"Wide strings converts hex values"); + Assert(uString(L"1.1").to_double()==1.1,"Wide strings converts doubles"); + + // UTF8 decoding + char s2b[]={0xC2,0x80,0x00}; + char d2b[]={0xC2,0x80,0xC2,0x80,0x00}; + char s3b[]={0xE0,0xA0,0x80,0x00}; + char d3b[]={0xE0,0xA0,0x80,0xE0,0xA0,0x80,0x00}; + char s4b[]={0xF0,0x90,0x80,0x80,0x00}; + char d4b[]={0xF0,0x90,0x80,0x80,0xF0,0x90,0x80,0x80,0x00}; + Assert(aString(s2b).length()==2,"2-byte UTF8 point can be stored"); + Assert(uString(s2b)==uString(s2b),"2-byte UTF8 point can be matched"); + Assert(uString(s2b)!=uString("."),"2-byte UTF8 point can be compared"); + Assert(uString(s2b).points()==1,"2-byte UTF8 point stored"); + Assert(uString(s2b).bytes()==2,"2-byte UTF8 point decoded"); + Assert(aString(d2b).length()==4,"2-byte UTF8 Sequence can be stored"); + Assert(uString(d2b).points()==2,"2-byte UTF8 Sequence stored"); + Assert(uString(d2b).bytes()==4,"2-byte UTF8 Sequence decoded"); + Assert(uString(d2b)==uString(d2b),"2-byte UTF8 Sequence can be matched"); + Assert(uString(d2b)!=uString(s2b),"2-byte UTF8 Sequence can be compared"); + Assert(aString(s3b).length()==3,"3-byte UTF8 point can be stored"); + Assert(uString(s3b)==uString(s3b),"3-byte UTF8 point can be matched"); + Assert(uString(s3b)!=uString(".."),"3-byte UTF8 point can be compared"); + Assert(uString(s3b).points()==1,"3-byte UTF8 point stored"); + Assert(uString(s3b).bytes()==3,"3-byte UTF8 point decoded"); + Assert(aString(d3b).length()==6,"3-byte UTF8 Sequence can be stored"); + Assert(uString(d3b).points()==2,"3-byte UTF8 Sequence stored"); + Assert(uString(d3b).bytes()==6,"3-byte UTF8 Sequence decoded"); + Assert(uString(d3b)==uString(d3b),"3-byte UTF8 Sequence can be matched"); + Assert(uString(d3b)!=uString(s2b),"3-byte UTF8 Sequence can be compared"); + Assert(aString(s4b).length()==4,"4-byte UTF8 point can be stored"); + Assert(uString(s4b)==uString(s4b),"4-byte UTF8 point can be matched"); + Assert(uString(s4b)!=uString("."),"4-byte UTF8 point can be compared"); + Assert(uString(s4b).points()==1,"4-byte UTF8 point stored"); + Assert(uString(s4b).bytes()==4,"4-byte UTF8 point decoded"); + Assert(aString(d4b).length()==8,"4-byte UTF8 Sequence can be stored"); + Assert(uString(d4b).points()==2,"4-byte UTF8 Sequence stored"); + Assert(uString(d4b).bytes()==8,"4-byte UTF8 Sequence decoded"); + Assert(uString(d4b)==uString(d4b),"4-byte UTF8 Sequence can be matched"); + Assert(uString(d4b)!=uString(s4b),"4-byte UTF8 Sequence can be compared"); +#endif + Assert(u.to_lower()=="test","ANSI strings converts to lower case"); + Assert(u.to_upper()=="TEST","ANSI strings converts to upper case"); + Assert(uString("10").to_int()==10,"ANSI strings converts integers"); + Assert(uString("10").to_int(16)==16,"ANSI strings converts hex values"); + Assert(uString("1.1").to_double()==1.1,"ANSI strings converts doubles"); + Assert(u[0]=="T" && u[1]=="e","Substring array works for ANSI strings"); + Assert(!strcmp(u.c_str(),"Test"),"ANSI string exports correctly"); + + // Test hashing + Header("String hashing"); + uString s0=""; + uString s1="abc"; + uString s2="abC"; + uString s3="bac"; + uString s4="abcc"; + uString s5="abc"; + Uint32 h1=EDL_HashString(s1); + Assert(h1!=0,"Hash produces non-zero values"); + Uint32 h0=EDL_HashString(s0); + Assert(h1!=h0,"Hash produces unique values"); + Uint32 h2=EDL_HashString(s2); + Assert(h1!=h2,"Hash identifies case changes"); + Uint32 h3=EDL_HashString(s3); + Assert(h1!=h3,"Hash identifies position changes"); + Uint32 h4=EDL_HashString(s4); + Assert(h1!=h4,"Hash identifies string changes"); + Uint32 h5=EDL_HashString(s5); + Assert(h1==h5,"Hash identifies string content"); + + // Sum up + Report(); +} + + diff --git a/engines/vileVN/testing/misctest.h b/engines/vileVN/testing/misctest.h new file mode 100644 index 0000000000..b5ea268d6d --- /dev/null +++ b/engines/vileVN/testing/misctest.h @@ -0,0 +1,12 @@ +#ifndef _MISCTEST_H_ +#define _MISCTEST_H_ + +#include "utest.h" + +class MiscTest : public UnitTest { + public: + MiscTest(); +}; + +#endif + diff --git a/engines/vileVN/testing/rwtest.cpp b/engines/vileVN/testing/rwtest.cpp new file mode 100644 index 0000000000..63cf5567f6 --- /dev/null +++ b/engines/vileVN/testing/rwtest.cpp @@ -0,0 +1,86 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "rwtest.h" + +RWTest::RWTest(){ + // Start by testing basic ram blobs + RWops *ops=new RWops(); + uString src="Testing blobs for ViLE"; + ops->OpenRAM((char*)src.c_str(),src.length(),false); + TestObject("Read/write RAM Blobs",ops,false); + ops->OpenROM(src.c_str(),src.length(),false); + TestObject("Read-only RAM Blobs",ops,true); + + // Create a temporary file and test writing + src=EDL_CreateTemporary()+"rwtest"; + Header("Writing with file blobs"); + Assert(ops->OpenFile(src.c_str(),"wb"),"Files opens for writing"); + Assert(ops->Size()==0,"Size starts at NULL"); + Assert(ops->Tell()==0,"Position pointer starts at NULL"); + Assert(ops->Seek(0,SEEK_END)==0,"Seeking to the end returns null"); + Assert(ops->Seek(0,SEEK_SET)==0,"Seeking to null returns null"); + Assert(ops->Write((void*)"Testing",1)==1,"Writing a byte returns one"); + Assert(ops->Tell()==1,"Position pointer increments at writing"); + Assert(ops->Seek(0,SEEK_END)==1,"Seeking to the end returns one"); + Assert(ops->Seek(0,SEEK_SET)==0,"Seeking to null returns null"); + Assert(ops->Size()==1,"Size is now one"); + Assert(ops->Write((void*)"Testing",1)==1,"Writing a byte returns one"); + Assert(ops->Tell()==1,"Position pointer increments at writing"); + Assert(ops->Seek(0,SEEK_END)==1,"Seeking to the end returns one"); + Assert(ops->Seek(0,SEEK_SET)==0,"Seeking to null returns null"); + Assert(ops->Size()==1,"Size is still one"); + Assert(ops->Write((void*)"Testing files",12)>1,"Writing strings works"); + Assert(ops->Tell()>1,"Position pointer increments at writing"); + Assert(ops->OpenFile(src.c_str(),"rb"),"Files reopens for reading"); + Assert(ops->Size()>0,"Size is larger than NULL"); + Assert(ops->Tell()==0,"Position pointer starts at NULL"); + TestObject("Read-only file blobs",ops,true); + EDL_DeleteFile(src); + Report(); +} + +void RWTest::TestObject(uString Name,RWops *Object,bool RO){ + Header(Name); + int size=Object->Size(); + char buffer[size]; + Assert(Object->Tell()==0,"Position pointer starts at NULL"); + Assert(Object->Seek(0,SEEK_END)==size,"Seeking to the end returns size"); + Assert(Object->Seek(0,SEEK_SET)==0,"Seeking to null returns null"); + Assert(Object->Size()>0,"Size is positive"); + Assert(Object->Size()<100,"Size seems correct"); + Assert(Object->Read(buffer,size/2)==size/2,"Read returns read bytes"); + Assert(Object->Tell()==size/2,"Position pointer updated after read"); + Assert(Object->Seek(0,SEEK_SET)==0,"Seeking works"); + Assert(Object->Read(buffer,1)==1,"Single byte reading works"); + Assert(Object->Read(buffer,1)==1,"Consequtive reading works"); + Assert(Object->Tell()==2,"Position pointer updated after read"); + Assert(Object->Read(buffer,size)==size-2,"Reads beyond buffer is blocked"); + Assert(Object->Read(buffer,size)==0,"Reads after eof is blocked"); + Assert(Object->Seek(0,SEEK_SET)==0,"Seeking still works"); + Assert(Object->Read(buffer,size)==size,"Reading entire buffer works"); + Assert(Object->Read(buffer,1)==0,"Reads after eof is blocked"); + Assert(Object->Seek(0,SEEK_SET)==0,"Seeking still works"); + if(RO){ + Assert(Object->Write(buffer,size)==0,"Writing is not permitted"); + Assert(Object->Size()==size,"Size is unchanged"); + } + else{ + Assert(Object->Write(buffer,size)==size,"Writing data works"); + Assert(Object->Size()==size,"Size is unchanged"); + } +} + + diff --git a/engines/vileVN/testing/rwtest.h b/engines/vileVN/testing/rwtest.h new file mode 100644 index 0000000000..7cad1eafd0 --- /dev/null +++ b/engines/vileVN/testing/rwtest.h @@ -0,0 +1,14 @@ +#ifndef _RWTEST_H_ +#define _RWTEST_H_ + +#include "utest.h" + +class RWTest : public UnitTest { + private: + void TestObject(uString Name,RWops *Object,bool RO); + public: + RWTest(); +}; + +#endif + diff --git a/engines/vileVN/testing/utest.cpp b/engines/vileVN/testing/utest.cpp new file mode 100644 index 0000000000..2d98e12342 --- /dev/null +++ b/engines/vileVN/testing/utest.cpp @@ -0,0 +1,112 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "utest.h" + +Uint32 UnitTest::total_passed=0; +Uint32 UnitTest::total_failed=0; +Uint32 UnitTest::total_time=0; + +UnitTest::UnitTest(){ + Reset(); + LogMessage(""); +} + +void UnitTest::Reset(){ + passed=failed=0; + start=SDL_GetTicks(); + round=start; +} + +uString UnitTest::RebuildString(uString String,va_list Arg){ + vsnprintf(buffer,UNIT_BUFFER_SIZE,String.c_str(),Arg); + buffer[UNIT_BUFFER_SIZE-1]=0; + return buffer; +} + +void UnitTest::Summary(){ + UnitTest test; + test.Header("Summary"); + test.Assert(total_passed+total_failed>0,"Test suite executed"); + test.Assert(total_failed==0,"All tests completed without errors"); + test.Assert(total_time<1000,"No test took too long"); + test.passed=total_passed; + test.failed=total_failed; + test.start=SDL_GetTicks()-total_passed; + test.Report(); +} + +void UnitTest::Report(){ + // Create header + uString dash; + Uint32 t=SDL_GetTicks()-start; + total_passed+=passed; + total_failed+=failed; + total_time+=t; + for(int i=0;i<76;i++) dash+="-"; + LogMessage(dash); + LogMessage("| Passed tests %59d |",passed); + LogMessage("| Failed tests %59d |",failed); + LogMessage("| Total number of tests %50d |",passed+failed); + LogMessage("| Passed %64d% |",(int)(passed/(double)(passed+failed)*100)); + LogMessage("| Execution time %54d mS |",t); + LogMessage(dash); + LogMessage(""); + LogMessage(""); +} + +void UnitTest::Header(uString Text,...){ + // Rebuild input string + va_list arg; + va_start(arg,Text); + Text=RebuildString(Text,arg); + va_end(arg); + + // Create header + uString dash; + for(int i=0;i<76;i++) dash+="-"; + LogMessage(dash); + LogMessage("| %-71s |",Text.c_str()); + LogMessage(dash); +} + +void UnitTest::Assert(bool Test,uString Text,...){ + // Rebuild textstring + va_list arg; + va_start(arg,Text); + Text=RebuildString(Text,arg); + va_end(arg); + + // Check test + uString result; + if(Test){ + result="PASS"; + passed++; + } + else{ + result="FAIL"; + failed++; + } + + // Format report entry + sprintf(buffer,"| % 4d %-53s % 5dmS %s |", + passed+failed, + Text.c_str(), + SDL_GetTicks()-round, + result.c_str()); + LogMessage(buffer); + round=SDL_GetTicks(); +} + diff --git a/engines/vileVN/testing/utest.h b/engines/vileVN/testing/utest.h new file mode 100644 index 0000000000..7bf0cc3dc4 --- /dev/null +++ b/engines/vileVN/testing/utest.h @@ -0,0 +1,42 @@ +#ifndef _UTEST_H_ +#define _UTEST_H_ + +#include "../common/log.h" +#include "../common/edl_fs.h" +#include "../common/edl_gfx.h" +#include "../common/dstack.h" +#include "../common/dvector.h" +#include "../common/darray.h" +#include "../common/stringlist.h" +#include "../common/inifile.h" +#include "../res/archives/abase.h" + +#define UNIT_BUFFER_SIZE 1024 + +class UnitTest { + private: + // Internal data + static Uint32 total_passed; + static Uint32 total_failed; + static Uint32 total_time; + char buffer[UNIT_BUFFER_SIZE]; + int passed,failed; + Uint32 start,round; + protected: + // Only derived objects please ... + UnitTest(); + + // Standard unittest API + void Header(uString Text,...); + void Assert(bool Test,uString Text,...); + void Report(); + void Reset(); + + // Format helper + uString RebuildString(uString String,va_list Arg); + public: + static void Summary(); +}; + +#endif + diff --git a/engines/vileVN/tlove/tlove.cpp b/engines/vileVN/tlove/tlove.cpp new file mode 100644 index 0000000000..677afb54e5 --- /dev/null +++ b/engines/vileVN/tlove/tlove.cpp @@ -0,0 +1,1236 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "tlove.h" + +#define GETBYTE(B) ((B)[0]) +#define GETWORD(B) ((B)[1]|((B)[0]<<8)) +#define GETDWORD(B) ((B)[3]|((B)[2]<<8)|((B)[1]<<16)|((B)[0]<<24)) + + +Truelove::Truelove(uString Path) : EngineVN(640,480){ + // Add resources + AddBGM(new ArchiveTLove(Path+"midi")); + AddSE(new ArchiveTLove(Path+"eff")); + AddScripts(new ArchiveTLove(Path+"date")); + AddImages(new ArchiveTLove(Path+"mrs")); + + // Set defaults + scriptdata=0; + scriptpos=0; + state=TLSTATE_NORMAL; + for(int i=0;iFill(0x000000FF); + textview->SetTextPosition(0,0,440,70); + textview->MoveDialog(100,396); + textview->Resize(440,70); + textview->Fill(0x000000FF); + + LoadTrueloveScript("MAIN"); +} + +Truelove::~Truelove(){ + Stop(); + for(int i=0;inextptr; + if(tmp->buffer){ + delete [] tmp->buffer; + } + delete tmp; + } + while(scriptpos){ + SCRIPTPOS *tmp=scriptpos; + scriptpos=scriptpos->nextptr; + delete tmp; + } +} + +/*! \brief Jumps to an position in the jumptable + * \param Position Jumptable position + * \return True if Jump was successfull + */ +bool Truelove::Jump(unsigned int Position){ + bool retval=false; + if(scriptpos){ + scriptpos->index=scriptdata->table.GetUint16(Position); + retval=true; + } + return retval; +} + +/*! \brief Allocates new position and performs jump + * \param Position Jumptable position + * \return True if Call was successfull + */ +bool Truelove::Call(unsigned int Position){ + bool retval=false; + if(scriptpos){ + SCRIPTPOS *pos=new SCRIPTPOS; + pos->index=scriptpos->index; + pos->data=scriptpos->data; + pos->nextptr=scriptpos; + scriptpos=pos; + retval=Jump(Position); + } + return retval; +} + +/*! \brief Returns from call by deallocating top position + * \return True if Return was successfull + */ +bool Truelove::Return(){ + bool retval=false; + if(scriptpos){ + SCRIPTPOS *pos=scriptpos; + scriptpos=scriptpos->nextptr; + if(scriptpos && scriptpos->data!=pos->data){ + // Change back to old script + while(scriptdata && scriptpos->data!=scriptdata){ + SCRIPTDATA *oldptr=scriptdata; + scriptdata=scriptdata->nextptr; + SCRIPTDATA *tmpptr=oldptr; + while(tmpptr->nextptr){ + tmpptr=tmpptr->nextptr; + } + scriptdata->nextptr=oldptr; + oldptr->nextptr=0; + } + + // Purge unnused scripts + Purge(); + } + delete pos; + retval=true; + } + return retval; +} + +/*! \brief Purges any scriptdata that is not reffered by any positions + */ +void Truelove::Purge(){ + SCRIPTDATA *tmpdata=scriptdata; + while(tmpdata){ + // Check if script is reffered by any active positions + bool hit=false; + SCRIPTPOS *tmppos=scriptpos; + while(tmppos){ + if(tmppos->data==tmpdata){ + hit=true; + break; + } + tmppos=tmppos->nextptr; + } + + if(hit){ + // Skip to next script + tmpdata=tmpdata->nextptr; + } + else if(tmpdata==scriptdata){ + // Remove head + LogVerbose("Purging scriptdata: %s",tmpdata->name.c_str()); + scriptdata=scriptdata->nextptr; + if(tmpdata->buffer){ + delete [] tmpdata->buffer; + } + delete tmpdata; + tmpdata=scriptdata; + } + else{ + // Find and remove from stack + LogVerbose("Purging scriptdata: %s",tmpdata->name.c_str()); + SCRIPTDATA *tmpptr=scriptdata; + while(tmpptr->nextptr!=tmpdata){ + tmpptr=tmpptr->nextptr; + } + tmpptr->nextptr=tmpdata->nextptr; + + if(tmpdata->buffer){ + delete [] tmpdata->buffer; + } + delete tmpdata; + tmpdata=tmpptr; + } + } +} + + +/*! \brief Loads a Truelove script and pushes it on top of the stack + * \param Script Name of the script file + * \return True if script loaded + */ +bool Truelove::LoadTrueloveScript(uString Script){ + bool retval=false; + RWops *blob=0; + if((blob=LoadScript(Script,"DAT"))){ + // Extract and verify data + LogVerbose("Loading Truelove script: %s",Script.c_str()); + int fulllength=blob->Seek(0,SEEK_END); + blob->Seek(0,SEEK_SET); + if(fulllength>(int)0){ + // Create a scriptdata structure + SCRIPTDATA *script=new SCRIPTDATA; + script->name=Script; + + // Get table length + unsigned char wbuffer[2]; + int scriptstart=0; + if(blob->Read(wbuffer,2)==2){ + scriptstart=GETWORD(wbuffer); + } + + // Read jumptable + int tablelength=scriptstart-12; + script->length=fulllength-(tablelength+2); + unsigned char tbuffer[tablelength+1]; + if(blob->Read(tbuffer,tablelength)==tablelength){ + for(int i=0;ilength){ + script->table.SetUint16(i/2,value); + } + else{ + LogError("Invalid table: %d/%d",value,script->length); + } + + } + } + + // Read version information + if(blob->Read(wbuffer,2)==2){ + char vbuffer[32]; + int vlength=GETWORD(wbuffer)-2; + if(blob->Read(vbuffer,vlength)>(int)0){ + vbuffer[vlength]=0; + script->length=script->length-(vlength+2); + LogVerbose("Reading Truelove version: %s",vbuffer+4); + } + } + + // Read script data + if(script->length>0){ + script->buffer=new unsigned char[script->length]; + unsigned int read=blob->Read(script->buffer,script->length); + if(read==script->length){ + retval=true; + } + else{ + delete [] script->buffer; + } + } + + // Stack the script and allocate a position + if(retval){ + SCRIPTPOS *pos=new SCRIPTPOS; + pos->index=0; + pos->data=script; + pos->nextptr=scriptpos; + scriptpos=pos; + script->nextptr=scriptdata; + scriptdata=script; + } + else{ + LogError("Failed to load script: %s",Script.c_str()); + delete script; + } + } + delete blob; + } + return retval; +} + +bool Truelove::EventLoad(int Index){ + bool retval=false; + return retval; +} + +bool Truelove::EventSave(int Index){ + return false; +} + +void Truelove::EventSelect(int Selection){ + if(scriptdata && (unsigned int)Selectionlength){ + Jump(Selection); + state=TLSTATE_NORMAL; + selection->SetVisible(false); + } +} + +bool Truelove::EventGameTick(){ + if(state==TLSTATE_WAITCLICK){ + bool skip=keyok || keyctrl() || GetSkipmode(); + if(skip && textview->GetRemainingText()){ + textview->CompleteText(); + keyok=false; + } + else if(skip){ + StopSound(VA_VOICES); + state=TLSTATE_NORMAL; + textview->ClearText(); + keyok=false; + } + } + return !(state==TLSTATE_NORMAL && !textview->GetRemainingText()); +} + +bool Truelove::EventGameProcess(){ + bool retval=true; + if(scriptpos && scriptdata && scriptpos->indexlength){ + unsigned int off=0; + unsigned int index=scriptpos->index; + Uint8 opcode=GETBYTE(scriptdata->buffer+index+off++); + Uint8 oplen=GETBYTE(scriptdata->buffer+index+off++); + if(oplen&0x80){ + oplen=GETBYTE(scriptdata->buffer+index+off++)|((oplen&0x7F)<<8); + } + if(index+off+oplen<=scriptdata->length){ + // Handle opcodes + //LogTest("OPCODE:%04d:%x (%d)",index,opcode,oplen); + scriptpos->index+=off; + Uint8 *opdata=scriptdata->buffer+scriptpos->index; + scriptpos->index+=oplen; + if(opcode==0x00) retval=OP00(opdata,oplen); + else if(opcode==0x04) retval=OP04(opdata,oplen); + else if(opcode==0x16) retval=OP16(opdata,oplen); + else if(opcode==0x17) retval=OP17(opdata,oplen); + else if(opcode==0x19) retval=OP19(opdata,oplen); + else if(opcode==0x1B) retval=OP1B(opdata,oplen); + else if(opcode==0x20) retval=OP20(opdata,oplen); + else if(opcode==0x23) retval=OP23(opdata,oplen); + else if(opcode==0x24) retval=OP24(opdata,oplen); + else if(opcode==0x28) retval=OP28(opdata,oplen); + else if(opcode==0x2B) retval=OP2B(opdata,oplen); + else if(opcode==0x30) retval=OP30(opdata,oplen); + else if(opcode==0x31) retval=OP31(opdata,oplen); + else if(opcode==0x32) retval=OP32(opdata,oplen); + else if(opcode==0x33) retval=OP33(opdata,oplen); + else if(opcode==0x34) retval=OP34(opdata,oplen); + else if(opcode==0x35) retval=OP35(opdata,oplen); + else if(opcode==0x36) retval=OP36(opdata,oplen); + else if(opcode==0x38) retval=OP38(opdata,oplen); + else if(opcode==0x39) retval=OP39(opdata,oplen); + else if(opcode==0x3A) retval=OP3A(opdata,oplen); + else if(opcode==0x3C) retval=OP3C(opdata,oplen); + else if(opcode==0x40) retval=OP40(opdata,oplen); + else if(opcode==0x41) retval=OP41(opdata,oplen); + else if(opcode==0x42) retval=OP42(opdata,oplen); + else if(opcode==0x43) retval=OP43(opdata,oplen); + else if(opcode==0x44) retval=OP44(opdata,oplen); + else if(opcode==0x48) retval=OP48(opdata,oplen); + else if(opcode==0x49) retval=OP49(opdata,oplen); + else if(opcode==0x4A) retval=OP4A(opdata,oplen); + else if(opcode==0x4B) retval=OP4B(opdata,oplen); + else if(opcode==0x4C) retval=OP4C(opdata,oplen); + else if(opcode==0x52) retval=OP52(opdata,oplen); + else if(opcode==0x53) retval=OP53(opdata,oplen); + else if(opcode==0x54) retval=OP54(opdata,oplen); + else if(opcode==0x61) retval=OP61(opdata,oplen); + else if(opcode==0x62) retval=OP62(opdata,oplen); + else if(opcode==0x63) retval=OP63(opdata,oplen); + else if(opcode==0x66) retval=OP66(opdata,oplen); + else if(opcode==0x67) retval=OP67(opdata,oplen); + else if(opcode==0x70) retval=OP70(opdata,oplen); + else if(opcode==0x71) retval=OP71(opdata,oplen); + else if(opcode==0x72) retval=OP72(opdata,oplen); + else if(opcode==0x73) retval=OP73(opdata,oplen); + else if(opcode==0x75) retval=OP75(opdata,oplen); + else if(opcode==0x82) retval=OP82(opdata,oplen); + else if(opcode==0x83) retval=OP83(opdata,oplen); + else if(opcode==0x84) retval=OP84(opdata,oplen); + else if(opcode==0x85) retval=OP85(opdata,oplen); + else if(opcode==0x86) retval=OP86(opdata,oplen); + else if(opcode==0x87) retval=OP87(opdata,oplen); + else if(opcode==0x89) retval=OP89(opdata,oplen); + else if(opcode==0x8A) retval=OP8A(opdata,oplen); + else if(opcode==0x91) retval=OP91(opdata,oplen); + else if(opcode==0x92) retval=OP92(opdata,oplen); + else if(opcode==0x95) retval=OP95(opdata,oplen); + else if(opcode==0x98) retval=OP98(opdata,oplen); + else if(opcode==0x99) retval=OP99(opdata,oplen); + else if(opcode==0x9D) retval=OP9D(opdata,oplen); + else if(opcode==0xA6) retval=OPA6(opdata,oplen); + else if(opcode==0xA7) retval=OPA7(opdata,oplen); + else if(opcode==0xAA) retval=OPAA(opdata,oplen); + else if(opcode==0xAD) retval=OPAD(opdata,oplen); + else if(opcode==0xAE) retval=OPAE(opdata,oplen); + else if(opcode==0xFF) retval=OPFF(opdata,oplen); + else{ + char buffer[3]; + uString code; + for(int i=0;i %d (%dx%d)", + // srci,srcx,srcy,srcw,srch,dsti,dstx,dsty); + if(srciBlit(cache[0]); + } + } + return (dsti==0); +} + +/*! Loads an animation + */ +bool Truelove::OP38(Uint8 *Data,Uint32 Size){ + char buffer[Size+1]; + strncpy(buffer,(char*)Data,Size-1); + buffer[Size]=0; + Uint8 param=GETBYTE(Data+Size-1); + LogTest("OP38:LOAD:ANIMATION:%s:%d",buffer,param); + return false; +} + +bool Truelove::OP39(Uint8 *Data,Uint32 Size){ + LogTest("OP39:%d",Size); + return false; +} + +/*! Fill rect + */ +bool Truelove::OP3A(Uint8 *Data,Uint32 Size){ + Uint16 p=GETWORD(Data+0); + Uint16 x=GETWORD(Data+2); + Uint16 y=GETWORD(Data+4); + Uint16 w=GETWORD(Data+6); + Uint16 h=GETWORD(Data+8); + Uint32 c=0xFF00FFFF; + if(p==0) c=0x000000FF; + else{ + LogTest("OP3A:FILL:%dx%dx%dx%d=%04X",x,y,w,h,p); + } + SDL_Rect r={x,y,w,h}; + display->Fill(c,&r); + return false; +} + +bool Truelove::OP3C(Uint8 *Data,Uint32 Size){ + Uint8 p1=GETBYTE(Data+0); + Uint16 p2=GETWORD(Data+1); + Uint16 p3=GETWORD(Data+3); + LogTest("OP3C:%d:%d:%d:%d",Size,p1,p2,p3); + return false; +} + +/* Hexrays: 40BEF0 + * Original calls 409D90 and 4054B0 + * + * 4054B0 + * return a3 & var[1][a2])!=0 + */ +bool Truelove::OP40(Uint8 *Data,Uint32 Size){ + Uint8 p1=GETBYTE(Data+0); + Uint8 p2=GETBYTE(Data+1); + Uint16 p3=GETWORD(Data+2); + if((p2 & vars[1].GetUint8(p1))!=0){ + Jump(p3); + } + return false; +} + +/* Conditional jump + * + * Hexrays: 40BF70 + * Original calls 409D90 and 4054B0 + */ +bool Truelove::OP41(Uint8 *Data,Uint32 Size){ + Uint8 p1=GETBYTE(Data+0); + Uint8 p2=GETBYTE(Data+1); + Uint16 p3=GETWORD(Data+2); + if((p2 & vars[0].GetUint8(p1))!=0){ + Jump(p3); + } + return false; +} + +/* Hexrays: 40BFF0 + * Original calls 409D90 and 4054D0 + * + */ +bool Truelove::OP42(Uint8 *Data,Uint32 Size){ + Uint8 p1=GETBYTE(Data+0); + Uint16 p2=GETWORD(Data+1); + LogTest("OP42:%d:%d",p1,p2); + return false; +} + +/* Hexrays: 40C0A0 + * Original calls 409D90 and 4052E0 + * + */ +bool Truelove::OP43(Uint8 *Data,Uint32 Size){ + if(Size==5){ + Uint8 flag=GETBYTE(Data+0); // Decode with 4052E0 + Uint8 op=GETBYTE(Data+1); + Uint8 i=GETWORD(Data+2); + Uint16 label=GETWORD(Data+4); + bool result=false; + switch(op){ + case 0: result=vars[2].GetUint8(flag)<=i; break; + case 1: result=vars[2].GetUint8(flag)==i; break; + case 2: result=vars[2].GetUint8(flag)>=i; break; + default: result=vars[2].GetUint8(flag)>=i; break; + } + if(result){ + LogError("OUCH ... Should have jumped here"); + //Jump(label); + } + } + else{ + LogError("Invalid OP43 length: %d",Size); + } + return false; +} + +/* Conditional jump + * + * Hexrays: 40C170 + * Original calls 409D90 and 40EEE0 + * + * 409D90(this,label) seems to be a jump + */ +bool Truelove::OP44(Uint8 *Data,Uint32 Size){ + if(Size==6){ + Uint8 flag=GETBYTE(Data+0); // Decode with 40EEE0 + Uint8 op=GETBYTE(Data+1); + Uint16 i=GETWORD(Data+2); + Uint16 label=GETWORD(Data+4); + bool result=false; + switch(op){ + case 0: result=vars[3].GetUint16(flag)<=i; break; + case 1: result=vars[3].GetUint16(flag)==i; break; + case 2: result=vars[3].GetUint16(flag)>=i; break; + default: result=vars[3].GetUint16(flag)>=i; break; + } + if(result){ + Jump(label); + } + } + else{ + LogError("Invalid OP44 length: %d",Size); + } + return false; +} + +/* Hexrays: 40C2D0 + * Calls 405410(this+8,p1,p2,1)) (Very similar to OP49) (vars[1]) + */ +bool Truelove::OP48(Uint8 *Data,Uint32 Size){ + Sint8 p1=GETBYTE(Data+0); + Sint8 p2=GETBYTE(Data+1); + int v=vars[1].GetUint32(1); + vars[1].SetUint32(p1,v|p1); + return false; +} + + +/* Hexrays: 40C310 + * Calls 405410(this+4,p1,p2,p3)) (Very similar to OP48) (vars[0]) + */ +bool Truelove::OP49(Uint8 *Data,Uint32 Size){ + Sint8 p1=GETBYTE(Data+0); + Sint8 p2=GETBYTE(Data+1); + Uint8 p3=GETBYTE(Data+2); + int v=vars[1].GetUint32(p3); + if(p3){ + vars[0].SetUint32(p1,v|p2); + } + else{ + vars[0].SetUint32(p1,v&(0xFFFFFF00|~p2)); + } + return false; +} + +bool Truelove::OP4A(Uint8 *Data,Uint32 Size){ + Uint8 p1=GETBYTE(Data+0); + Sint8 p2=GETBYTE(Data+1); + + LogTest("OP4A:%d:%d:%d",Size,p1,p2); + return false; +} + +/* Hexrays: 40C420 + * Uses 4052F0 to add value, 4052A0 to set it + */ +bool Truelove::OP4B(Uint8 *Data,Uint32 Size){ + Uint8 p1=GETBYTE(Data+0); + Sint8 p2=GETBYTE(Data+1); + if(p2){ + Sint8 v=vars[2].GetUint8(p1); + vars[2].SetUint8(p1,p2+v); + } + else{ + vars[2].SetUint8(p1,0); + } + LogTest("OP4B:%d:%d:%d",Size,p1,p2); + return false; +} + +/* Hexrays: 40C4A0 + * Uses 40EED0 to add value, 40EE80 to set it + */ +bool Truelove::OP4C(Uint8 *Data,Uint32 Size){ + Uint8 p1=GETBYTE(Data+0); + Sint16 p2=GETWORD(Data+1); + if(p2){ + Sint16 v=vars[3].GetUint16(p1); + vars[3].SetUint16(p1,p2+v); + } + else{ + vars[3].SetUint16(p1,0); + } + LogTest("OP4C:%d:%d:%d",Size,p1,p2); + return false; +} + +/*! Load script + */ +bool Truelove::OP52(Uint8 *Data,Uint32 Size){ + char buffer[Size+1]; + strncpy(buffer,(char*)Data,Size-1); + buffer[Size]=0; + //Uint8 param=GETBYTE(Data+Size-1); + LogTest("OP52:LOAD:%s",buffer); + LoadTrueloveScript(buffer); + return false; +} + +/*! Play animation + */ +bool Truelove::OP53(Uint8 *Data,Uint32 Size){ + Uint8 p1=GETBYTE(Data+0); + Uint8 p2=GETBYTE(Data+1); + Uint8 p3=GETBYTE(Data+2); + LogTest("OP53:PLAY:ANIMATION:%d:%d:%d",p1,p2,p3); + return false; +} + +bool Truelove::OP54(Uint8 *Data,Uint32 Size){ + Uint16 p1=GETWORD(Data+0); + Uint8 p2=GETBYTE(Data+2); + Uint16 p3=GETWORD(Data+3); + LogTest("OP54:%d:%d:%d",p1,p2,p3); + return false; +} + +/*! Play music + */ +bool Truelove::OP61(Uint8 *Data,Uint32 Size){ + char buffer[Size]; + strncpy(buffer,(char*)Data,Size-2); + buffer[Size-1]=0; + //Uint16 loop=GETWORD(Data+Size-2); + PlayMusic(buffer); + return false; +} + +bool Truelove::OP62(Uint8 *Data,Uint32 Size){ + LogTest("OP62:%d",Size); + return false; +} + +/*! Stop music + */ +bool Truelove::OP63(Uint8 *Data,Uint32 Size){ + StopMusic(); + return false; +} + +/*! Play sound + */ +bool Truelove::OP66(Uint8 *Data,Uint32 Size){ + char buffer[Size]; + strncpy(buffer,(char*)Data,Size-2); + buffer[Size-1]=0; + LogTest("OP66:PLAY:SE:%s",buffer); + return false; +} + +bool Truelove::OP67(Uint8 *Data,Uint32 Size){ + LogTest("OP67:%d",Size); + return false; +} + +/*! Dialog text + */ +bool Truelove::OP70(Uint8 *Data,Uint32 Size){ + // Parse parameters + int start=3; + //Uint8 p1=GETBYTE(Data+0); + Uint8 p2=GETBYTE(Data+1); + //Uint8 p3=GETBYTE(Data+2); + Uint8 p4=0; + Uint8 p5=0; + Uint8 p6=0; + if(p2!=0xFF){ + p4=GETBYTE(Data+3); + p5=GETBYTE(Data+4); + p6=GETBYTE(Data+5); + start=6; + } + + uString text; + if(Size-start>0){ + char buffer[(Size-start)+1]; + strncpy(buffer,(char*)Data+start,Size-start); + buffer[Size-start]=0; + text=buffer; + } + textview->PrintText(text); + return false; +} + +/*! Print text + */ +bool Truelove::OP71(Uint8 *Data,Uint32 Size){ + // Parse parameters + Uint16 x=GETWORD(Data+0); + Uint16 y=GETWORD(Data+2); + Uint8 c=GETBYTE(Data+4); + uString text; + if(Size-5>0){ + char buffer[(Size-5)+1]; + strncpy(buffer,(char*)Data+5,Size-5); + buffer[Size-5]=0; + text=buffer; + } + LogTest("OP71:PRINT:TEXT:%s:%d:%dx%d",text.c_str(),c,x,y); + return false; +} + +bool Truelove::OP72(Uint8 *Data,Uint32 Size){ + Uint8 p=GETBYTE(Data+0); + LogTest("OP72:%d",Size); + return false; +} + +bool Truelove::OP73(Uint8 *Data,Uint32 Size){ + Uint8 p=GETBYTE(Data+0); + LogTest("OP73:Open font %d",p); + return false; +} + +bool Truelove::OP75(Uint8 *Data,Uint32 Size){ + Sint8 p1=GETBYTE(Data+0); + Uint8 p2=GETBYTE(Data+1); + Uint8 p3=GETBYTE(Data+2); + LogTest("OP75:%d:%d:%d",p1,p2,p3); + return false; +} + +bool Truelove::OP82(Uint8 *Data,Uint32 Size){ + Uint16 p1=GETWORD(Data+0); + Uint16 p2=GETWORD(Data+2); + Uint16 p3=GETWORD(Data+4); + Uint16 p4=GETWORD(Data+6); + Uint8 p5=GETBYTE(Data+8); + LogTest("OP82:%d:%d:%d:%d:%d",p1,p2,p3,p4,p5); + return false; +} + +bool Truelove::OP83(Uint8 *Data,Uint32 Size){ + Uint16 p=GETWORD(Data+0); + LogTest("OP83:%d",p); + return false; +} + +bool Truelove::OP84(Uint8 *Data,Uint32 Size){ + char buffer[Size]; + strncpy(buffer,(char*)Data,Size-1); + buffer[Size-1]=0; + Uint8 p=GETBYTE(Data+Size-1); + LogTest("OP84:INTERFACE:%s:%d",buffer,p); + return false; +} + +bool Truelove::OP85(Uint8 *Data,Uint32 Size){ + Sint8 p1=GETWORD(Data+0); + Uint8 p2=GETWORD(Data+1); + LogTest("OP85:INTERFACE:%d %d (%d)",p1,p2,Size); + return false; +} + +bool Truelove::OP86(Uint8 *Data,Uint32 Size){ + Uint16 p1=GETWORD(Data+0); + Uint16 p2=GETWORD(Data+2); + Sint8 p3=GETWORD(Data+4); + Uint8 p4=GETWORD(Data+5); + LogTest("OP86:INTERFACE:%d %d %d %d",p1,p2,p3,p4); + return false; +} + +bool Truelove::OP87(Uint8 *Data,Uint32 Size){ + char buffer[Size]; + strncpy(buffer,(char*)Data,Size-1); + buffer[Size-1]=0; + Uint8 p=GETBYTE(Data+Size-1); + LogTest("OP87:INTERFACE:%s:%d",buffer,p); + return false; +} + +/*! Delay + */ +bool Truelove::OP89(Uint8 *Data,Uint32 Size){ + Uint16 delay=GETWORD(Data+0); + SDL_Delay(delay); + return false; +} + +/*! Update screen + */ +bool Truelove::OP8A(Uint8 *Data,Uint32 Size){ + return true; +} + +/*! Return from call + */ +bool Truelove::OP91(Uint8 *Data,Uint32 Size){ + Return(); + return false; +} + +bool Truelove::OP92(Uint8 *Data,Uint32 Size){ + LogTest("OP92:%d",Size); + return false; +} + +/*! Set range of flags + * + * Hexrays: 40D960 + * + * Type 0 => 405440(this+4,int) => 4053D0 + * Type 1 => 405440(this+8,int) => 4053D0 + * Type 2 => 4052B0(this+12,byte) + * Type 3 => 40EE90(this+16,word) + */ +bool Truelove::OP95(Uint8 *Data,Uint32 Size){ + Uint8 type=GETBYTE(Data+0); + Uint16 flag=GETWORD(Data+1); + Uint16 count=GETWORD(Data+3); + Uint8 value=GETBYTE(Data+5); + for(int i=flag;i0x03)){ + LogError("Unknown flag operation: %d",op); + break; + } + + if(pos++ & 2){ + switch(op){ + case 0: r=z; break; + case 1: r-=z; break; + case 2: r*=z; break; + case 3: if(z) r/=z; break; + } + } + else{ + switch(op){ + case 0: l+=z; break; + case 1: l-=z; break; + case 2: l+=r*z; break; + case 3: if(z) l+=r/z; break; + } + } + } + vars[3].SetUint16(flag&0x7FFF,l+r); + LogTest("SET FLAG[%d]=%d",flag&0x7FFF,l+r); + } + else{ + LogError("Variable not in FLAG_SET bank: 0x%04X",flag); + } + return false; +} + +bool Truelove::OP99(Uint8 *Data,Uint32 Size){ + LogTest("OP99:SET FLAG RELATED:%d",Size); + return false; +} + +bool Truelove::OP9D(Uint8 *Data,Uint32 Size){ + Uint8 p1=GETBYTE(Data+0); + Uint8 p2=GETBYTE(Data+1); + LogTest("OP9D:%d:%d",Size,p1,p2); + if(p2){ + // Update animation or sprite index p1? + } + else{ + // Flush anumation/sprite + } + return false; +} + +/*! Wait for user input + */ +bool Truelove::OPA6(Uint8 *Data,Uint32 Size){ + Uint16 p1=GETWORD(Data+0); + Uint16 p2=GETWORD(Data+2); + if(p1!=1 || p2!=1){ + LogTest("OPA6:WAIT:%d:%d",p1,p2); + } + state=TLSTATE_WAITCLICK; + return true; +} + +/*! Detect mouse clicks + */ +bool Truelove::OPA7(Uint8 *Data,Uint32 Size){ + Uint16 x1=GETWORD(Data+0); + Uint16 y1=GETWORD(Data+2); + Uint16 x2=GETWORD(Data+4); + Uint16 y2=GETWORD(Data+6); + Uint16 label=GETWORD(Data+8); + + /* + if(MOUSECLICK){ + JUMP(LABEL); + } + */ + + LogTest("OPA7:CLICKDETECT:%dx%dx%dx%d:%d",x1,y1,x2,y2,label); + return false; +} + +bool Truelove::OPAA(Uint8 *Data,Uint32 Size){ + Uint16 x1=GETWORD(Data+0); + Uint16 y1=GETWORD(Data+2); + Uint16 x2=GETWORD(Data+4); + Uint16 y2=GETWORD(Data+6); + + LogTest("OPA7:%dx%dx%dx%d",x1,y1,x2,y2); + return false; +} + +/*! Invalidates on keyboard/mouse ... ? + */ +bool Truelove::OPAD(Uint8 *Data,Uint32 Size){ + /* Original processes peripherals here and store states in registers + + Uint16 left=GETWORD(Data+0); + Uint16 right=GETWORD(Data+2); + Uint16 miss=GETWORD(Data+4); // Decodes with 409DD0 + Uint8 count=GETBYTE(Data+6); + */ + return false; +} + +/*! Detect mouse events + */ +bool Truelove::OPAE(Uint8 *Data,Uint32 Size){ + Uint16 x1=GETWORD(Data+0); + Uint16 y1=GETWORD(Data+2); + Uint16 x2=GETWORD(Data+4); + Uint16 y2=GETWORD(Data+6); + Uint16 label=GETWORD(Data+8); + //Uint8 type=GETWORD(Data+10); + //Uint16 flag=GETWORD(Data+11); + + // We access system values directly + int mx=mousex; + int my=mousey-display->GetY(); + if(mx>=x1 && mx=y1 && myReadFile(EDL_Realname(Path+"mesiaus.suf"))){ + uString gamekey,gametitle="unknown"; + if(inifile->Get("Key",gamekey)){ + if(ProbeString(gamekey,"mesiaius")){ + retval=true; + } + } + } + } + return retval; +} + +bool ViLE::ProbeJUMC(uString Path){ + // Check for key files + LogVerbose("Probing for JAST USA Memorial Collection:"); + return (ProbeResource(Path,"data/images.pck") && + ProbeResource(Path,"data/data.pck") && + ProbeResource(Path,"data/frames.pck")); +} + +bool ViLE::ProbeDiviDead(uString Path){ + // Check for key files + LogVerbose("Probing for DiviDead:"); + return (ProbeResource(Path,"sg.dl1") && + ProbeResource(Path,"wv.dl1")); +} + +bool ViLE::ProbeTrueLove(uString Path){ + // Check for key files + LogVerbose("Probing for True love:"); + return (ProbeResource(Path,"eff") && + ProbeResource(Path,"mrs") && + (ProbeResource(Path,"date") || + ProbeResource(Path,"datg"))); +} + +bool ViLE::ProbeYumeMiruKusuri(uString Path){ + // Check for key files + LogVerbose("Probing for Yume Miru Kusuri:"); + return (ProbeResource(Path,"rio.arc") && + ProbeResource(Path,"chip.arc") && + (ProbeSize(Path+"rio.arc",1828524) || + ProbeSize(Path+"rio.arc",1828457))); +} + +bool ViLE::ProbeCriticalPoint(uString Path){ + // Check for key files + LogVerbose("Probing for Critical Point:"); + return (ProbeResource(Path,"rio.arc") && + ProbeResource(Path,"chip.arc") && + ProbeSize(Path+"rio.arc",986745)); +} + +bool ViLE::ProbeTokimeki(uString Path){ + // Check for key files + LogVerbose("Probing for Tokimeki Check-in!:"); + return (ProbeResource(Path,"scene00.bdt") && + ProbeResource(Path,"353-103.zbm") && + ProbeResource(Path,"indexw.dat")); +} + +bool ViLE::ProbeXChange1(uString Path){ + // Check for key files + LogVerbose("Probing for XChange 1:"); + return (ProbeResource(Path,"scene00.bdt") && + ProbeResource(Path,"207-30l2.zbm") && + ProbeResource(Path,"index.dat")); +} + +bool ViLE::ProbeXChange3(uString Path){ + // Check for key files + LogVerbose("Probing for XChange 3:"); + return (ProbeResource(Path,"xc3.sce") && + ProbeResource(Path,"voice/xc3.pck")); +} + +/*! \brief Checks existence of resource file and logs verbosely + * \param Path Directory + * \param Resource Filename path relative to Path + * \return True if file exists + */ +bool ViLE::ProbeResource(uString Path,uString Resource){ + uString path=EDL_Realname(Path+Resource); + bool retval=EDL_ReadableFile(path); + LogVerbose("\t%-40s%s",path.c_str(),retval?"PASS":"FAIL"); + return retval; +} + +/*! \brief Checks if two strings matches and logs verbosely + * \param S1 String + * \param S2 String to compare with + * \return True if the strings matches (case insensitive) + */ +bool ViLE::ProbeString(uString S1,uString S2){ + S1=EDL_Lower(S1); + S2=EDL_Lower(S2); + bool retval=(S1==S2); + uString msg=S1+uString(" == ")+S2; + LogVerbose("\t%-40s%s",msg.c_str(),retval?"PASS":"FAIL"); + return retval; +} + +/*! \brief Checks size of a file and logs verbosely + * \param Path Path to file + * \param Size Expected size + * \return True if file exists and size matches + */ +bool ViLE::ProbeSize(uString Path,unsigned int Size){ + bool retval=false; + int compare=-1; + uString path=EDL_Realname(Path); + FILE *test=fopen(path.c_str(),"rb"); + if(test){ + fseek(test,0,SEEK_END); + compare=ftell(test); + retval=(compare==(int)Size); + fclose(test); + } + LogVerbose("\t%-40s%d/%d",path.c_str(),compare,Size); + return retval; +} + +/*! \brief Confirms a IkuraGDL title using a SUF file + * \param Path Folder to load resources from + * \param Key Key to confirm + * \return True if title resources was confirmed + */ +bool ViLE::ProbeSUF(uString Path,uString Key){ + // Check for key files + bool retval=0; + bool isf=ProbeResource(Path,"ggd") && ProbeResource(Path,"isf"); + bool drs=ProbeResource(Path,"drsgrp") && ProbeResource(Path,"drssnr"); + if(isf || drs){ + // Get SUF file + uString sufname; + if(ProbeResource(Path,"game.suf")) sufname="game.suf"; + else if(ProbeResource(Path,Key+".suf")) sufname=Key+".suf"; + else if(ProbeResource(Path,Key+"us.suf")) sufname=Key+"us.suf"; + else if(ProbeResource(Path,Key+"ml.suf")) sufname=Key+"ml.suf"; + + // Confirm title + if(sufname.length()){ + INIFile *inifile=new INIFile(false); + LogVerbose("Parsing SUF: %s",sufname.c_str()); + if(inifile->ReadFile(EDL_Realname(Path+sufname))){ + uString gamekey,gametitle="unknown"; + if(inifile->Get("Key",gamekey)){ + if(ProbeString(gamekey,Key) || + ProbeString(gamekey,Key+"us") || + ProbeString(gamekey,Key+"ml")){ + retval=true; + } + } + } + delete inifile; + } + } + return retval; +} + +void ViLE::RunEngine(EngineVN *engine){ + // Load screen surface and set a caption + SDL_Surface *screen=SDL_GetVideoSurface(); + uString caption=engine->NativeName(); + if(caption!=PACKAGE_STRING){ + uString pstring=uString(PACKAGE_STRING); + uString pcode=uString(PACKAGE_LINE); + caption=pstring+uString(" (")+pcode+uString("): ")+caption; + } + else{ + uString pstring=uString(PACKAGE_STRING); + uString pcode=uString(PACKAGE_LINE); + caption=pstring+uString(" (")+pcode+uString(")"); + } + SDL_WM_SetCaption(caption.c_str(),NULL); + + // Discard old and fake events + SDL_Event event; + while(SDL_PollEvent(&event)); + + // Load system settings + engine->EventLoadSystem(); + + // Drive engine + while(engine){ + // Tick engine + engine->EventHostTick(); + + // Redraw screen + if(engine->EventHostPaint(screen)){ + SDL_Flip(screen); + } + + // Handle events + while(engine && SDL_PollEvent(&event)){ + if(event.type==SDL_MOUSEMOTION){ + // Basic mousemove event + engine->EventHostMouseMove( + screen,event.motion.x, + event.motion.y); + } + else if(event.type==SDL_MOUSEBUTTONDOWN){ + // Left mouse button + if(event.button.button==SDL_BUTTON_RIGHT){ + engine->EventHostMouseRightDown( + screen,event.motion.x, + event.motion.y); + } + else{ + engine->EventHostMouseLeftDown( + screen,event.motion.x, + event.motion.y); + } + } + else if(event.type==SDL_MOUSEBUTTONUP){ + // Left mouse button + if(event.button.button==SDL_BUTTON_RIGHT){ + engine->EventHostMouseRightUp( + screen,event.motion.x, + event.motion.y); + } + else{ + engine->EventHostMouseLeftUp( + screen,event.motion.x, + event.motion.y); + } + } + else if(event.type==SDL_KEYDOWN){ + engine->EventHostKeyDown(event.key.keysym.sym); + } + else if(event.type==SDL_KEYUP){ + engine->EventHostKeyUp(event.key.keysym.sym); + } + else if(event.type==SDL_QUIT){ + if(engine->GetShutdown()){ + // Shut down engine and break out of loop + engine->EventSaveSystem(); + delete engine; + engine=0; + } + else{ + // Request shutdown + engine->EventGameDialog(VD_SHUTDOWN); + } + } + } + + // Purge deleted objects + Group::Purge(); + } +} + +EngineVN *ViLE::LoadEngine(uString Path){ + // Assert trailing separator + Path=EDL_StripPath(Path); + int i=Path.length(); + if(i && Path[i-1]!='/' && Path[i-1]!='\\'){ +#ifdef VILE_ARCH_MICROSOFT + Path+="\\"; +#else + Path+="/"; +#endif + } + + // Try to load a game + EngineVN *engine=0; + if(0){ + } +#ifdef VILE_SUPPORT_WINDY + else if(ProbeNocturnal(Path)) engine=new Nocturnal(Path); + else if(ProbeMayclub(Path)) engine=new Mayclub(Path); +#endif +#ifdef VILE_SUPPORT_JAST + else if(ProbeJUMC(Path)) engine=new JUMC(Path); +#endif +#ifdef VILE_SUPPORT_CWARE + else if(ProbeDiviDead(Path)) engine=new DiviDead(Path); +#endif +#ifdef VILE_SUPPORT_WILL + else if(ProbeYumeMiruKusuri(Path)) engine=new YumeMiruKusuri(Path); + else if(ProbeCriticalPoint(Path)) engine=new CriticalPoint(Path); +#endif +#ifdef VILE_SUPPORT_TLOVE + else if(ProbeTrueLove(Path)) engine=new Truelove(Path); +#endif +#ifdef VILE_SUPPORT_IKURA + else if(ProbeCrescendo(Path)) engine=new Crescendo(Path); + else if(ProbeSagara(Path)) engine=new Sagara(Path); + else if(ProbeSnow(Path)) engine=new Snow(Path); + else if(ProbeKanaOkaeri(Path)) engine=new KanaOkaeri(Path); + else if(ProbeKana(Path)) engine=new Kana(Path); + else if(ProbeHitomi(Path)) engine=new Hitomi(Path); + else if(ProbeCatGirl(Path)) engine=new CatGirl(Path); + else if(ProbeIdols(Path)) engine=new Idols(Path); +#endif +#ifdef VILE_SUPPORT_CROWD + else if(ProbeTokimeki(Path)) engine=new Tokimeki(Path); + else if(ProbeXChange1(Path)) engine=new XChange1(Path); + else if(ProbeXChange3(Path)) engine=new XChange3(Path); +#endif + else ; + return engine; +} + +/*! \brief Initializes (or resizes) video the display surface + * \return True if the video surface could be created + * + * This method will use the configuration settings, and can be executed + * multiple times in case you want to reload the settings and resize the + * display. + */ +bool ViLE::InitVideo(){ + // Assert configuration + bool retval=false; + static Uint32 ow=0; + static Uint32 oh=0; + Uint32 w=Cfg::Display::Width; + Uint32 h=Cfg::Display::Height; + Uint32 d=Cfg::Display::Depth; + Uint32 f=Cfg::Display::Flags; + if(!w || !h){ + w=DEFAULT_WIDTH; + h=DEFAULT_HEIGHT; + } + + if(w && h && ow==w && oh==h){ + // Changing size to the same size ... + retval=true; + } + else if(SDL_SetVideoMode(w,h,d,f)!=0){ + // Resized surface + retval=true; + ow=w; + oh=h; + } + else{ + LogError("Failed to create display surface: %s",SDL_GetError()); + } + return retval; +} + +bool ViLE::InitSystem(Uint32 Systemflags){ + // Initialize SDL and load application object + bool retval=false; + if (SDL_Init(Systemflags)<0) { + LogError("SDL Initialization error: %s",SDL_GetError()); + } + else if(TTF_Init()<0){ + LogError("Could not init TrueType: %s\n",TTF_GetError()); + } + else if(IMG_Init(IMG_INIT_JPG|IMG_INIT_PNG)==0){ + LogError("Failed to link to any image libraries: %s\n",IMG_GetError()); + } + else{ +#ifdef VILE_FEATURE_FFMPEG + avcodec_register_all(); + av_register_all(); +#endif + retval=true; + } +#ifdef VILE_BUILD_W32CONSOLE + RedirectIOToConsole(); +#endif + return retval; +} + +void ViLE::Quit(){ + // Close internal systems + Media::Close(); + + // Close down dependencies + IMG_Quit(); + TTF_Quit(); + SDL_Quit(); +} + +void ViLE::Help(){ + // Show available options + About(); + LogMessage("Usage: vilevn [OPTIONS|COMMAND]"); + LogMessage(""); + LogMessage("Display settings:"); + LogMessage("\t--fullscreen\t\t\tForces fullscreen mode"); + LogMessage("\t--size WIDTH HEIGHT\t\tSet screen size"); + LogMessage("\t--depth 8|16|24|32\t\tSet bit per pixel for screen"); + LogMessage("\t--fontface PATH\t\t\tDefault truetype font file"); + LogMessage("\t--fontsize SIZE\t\t\tDefault font size (pixel height)"); + LogMessage(""); + LogMessage("Audio configuration:"); + LogMessage("\t--disable-audio\t\t\tDo not load any audio resources"); + LogMessage("\t--disable-midi\t\t\tDo not load MIDI tracks or soundfonts"); + LogMessage("\t--cdrom INDEX\t\t\tSet source for CDDA audio (=auto)"); + LogMessage("\t--samplerate SAMPLERATE\t\tSamples per second (=44100)"); + LogMessage("\t--buffersize BYTES\t\tBytes per frame (=1024)"); + LogMessage("\t--buffercount NUMBER\t\tBuffered frames (=4)"); + LogMessage("\t--soundfont FILENAME\t\tSoundfont for MIDI synthesizer"); + LogMessage(""); + LogMessage("Video configuration:"); + LogMessage("\t--disable-video\t\t\tDo not load any video resources"); + LogMessage("\t--disable-overlay\t\tDisable hardware video rendering"); + LogMessage(""); + LogMessage("Other:"); + LogMessage("\t--config PATH\t\t\tSpecify configuration file"); + LogMessage("\t--cwd FOLDER\t\t\tSet current working directory"); + LogMessage("\t--game FOLDER\t\t\tLoad game from specified path"); + LogMessage("\t--save FOLDER\t\t\tPath for savegames"); + LogMessage("\t--disable-menu\t\t\tDo not show application menu bar"); + LogMessage("\t--logcolor\t\t\tFormat log output with colors"); + LogMessage("\t--logfile PATH\t\t\tSpecify output log file"); + LogMessage("\t--keyfile PATH\t\t\tLoad encryption key from file"); + LogMessage("\t--verbose\t\t\tPrint additional runtime information"); + LogMessage("\t--dryrun\t\t\tLoad as usual but prevent from starting"); + LogMessage("\t--info [title|res|runtime]\tDisplay runtime information"); + LogMessage(""); + LogMessage("Commands:"); +#if VILE_FEATURE_UNITTEST + LogMessage("\t--unittest all||...\t\tUnit-test core class' functionality"); + LogMessage("\t--benchmark all|...\t\tBenchmark core class' performance"); +#endif + LogMessage("\t--list ARC\t\t\tLists resources in archive"); + LogMessage("\t--extract ARC [RES [RES ..]]\tExtract resource from archive"); + LogMessage("\t--decode INFILE [INFILE ..]\tDecode resources"); + LogMessage("\t--xdec ARC [RES [RES ..]]\tExtract AND decode resources"); + LogMessage("\t--archive ARC INFILE [INFILE..]\tArchives resources"); + LogMessage("\t--help\t\t\t\tThis helpfull message"); + LogMessage("\t--about\t\t\t\tAbout ViLE"); + LogMessage(""); + LogMessage(""); + LogMessage("You can also use the following hotkeys at runtime:"); + LogMessage("\tALT+1\t\t\t\tNo graphic filters"); + LogMessage("\tALT+3\t\t\t\tHQ2X graphic filter"); + LogMessage("\tALT+4\t\t\t\tHQ3X graphic filter"); + LogMessage("\tALT+5\t\t\t\tHQ4X graphic filter"); + LogMessage("\tALT+ENTER\t\t\tToggle fullscreen mode"); + LogMessage("\tALT+F4\t\t\t\tExit"); + LogMessage("\tF5\t\t\t\tLoad game"); + LogMessage("\tF6\t\t\t\tSave game"); + LogMessage("\tF7\t\t\t\tOptions dialog"); + LogMessage("\tF8\t\t\t\tTitle screen"); + LogMessage("\tF9\t\t\t\tExit"); + LogMessage("\tF10\t\t\t\tDump screenshot to file"); + LogMessage("\tF11\t\t\t\tToggle debug output"); + LogMessage(""); +} + +void ViLE::About(){ + LogMessage(""); + LogMessage("Visual Library Engine"); + LogMessage("%s (%s, Rev:%s)",PACKAGE_STRING,PACKAGE_LINE,SCM_VERSION); + LogMessage("2011 (C) ViLE Team "); + LogMessage("Released under GNU GPLv3 "); + LogMessage(""); +} + +void ViLE::InfoTitle(EngineVN *Engine){ + LogMessage("Game information:"); + LogMessage("\tID:%s",Engine->NativeID().c_str()); + LogMessage("\tName:%s",Engine->NativeName().c_str()); + LogVerbose("\tDirectory: %s",Cfg::Path::game.c_str()); + LogMessage("\tResolution:%dx%d", + Engine->NativeWidth(), + Engine->NativeHeight()); +} + +void ViLE::InfoResources(EngineVN *Engine){ + Stringlist list; + LogMessage("Resource information:"); + if(Engine->GetVoices(&list)){ + LogMessage("\tVoices:%s",list.Enumerate().c_str()); + } + if(Engine->GetScripts(&list)){ + LogMessage("\tScripts:%s",list.Enumerate().c_str()); + } + if(Engine->GetImages(&list)){ + LogMessage("\tImages:%s",list.Enumerate().c_str()); + } + if(Engine->GetBGM(&list)){ + LogMessage("\tBGM:%s",list.Enumerate().c_str()); + } + if(Engine->GetSE(&list)){ + LogMessage("\tSE:%s",list.Enumerate().c_str()); + } + if(Engine->GetVideo(&list)){ + LogMessage("\tVideo:%s",list.Enumerate().c_str()); + } + if(Engine->GetOther(&list)){ + LogMessage("\tOther:%s",list.Enumerate().c_str()); + } +} + +void ViLE::InfoRuntime(){ + // Dump compiletime information + LogMessage("Version information"); + LogMessage("\tCompiled: %s",COMPILATION_DATE); + LogMessage("\tVersion: %s (%s)",PACKAGE_STRING,PACKAGE_LINE); + LogMessage("\tRevision: %s",SCM_VERSION); +#if VILE_ARCH_MICROSOFT + LogMessage("\tArch: Windows"); +#elif VILE_ARCH_LINUX + LogMessage("\tArch: Linux"); +#elif VILE_ARCH_FREEBSD + LogMessage("\tArch: FreeBSD"); +#else + LogMessage("\tArch: UNSUPPORTED"); +#endif + + // List enabled engines + LogMessage("\r\nEnabled sub-engines"); +#if VILE_SUPPORT_WINDY + LogMessage("\tWindy"); +#endif +#if VILE_SUPPORT_IKURA + LogMessage("\tIkuraGDL"); +#endif +#if VILE_SUPPORT_JAST + LogMessage("\tJAST Engine"); +#endif +#if VILE_SUPPORT_CROWD + LogMessage("\tCrowd Engine 3"); +#endif + + // List linked library version numbers + LogMessage("\r\nLinked libraries"); + LogMessage("\tSDL:\t\t%d.%d.%d", + SDL_MAJOR_VERSION, + SDL_MINOR_VERSION, + SDL_PATCHLEVEL); + LogMessage("\tSDL_gfx:\t%d.%d.%d", + SDL_GFXPRIMITIVES_MAJOR, + SDL_GFXPRIMITIVES_MINOR, + SDL_GFXPRIMITIVES_MICRO); + LogMessage("\tSDL_image:\t%d.%d.%d", + SDL_IMAGE_MAJOR_VERSION, + SDL_IMAGE_MINOR_VERSION, + SDL_IMAGE_PATCHLEVEL); + LogMessage("\tSDL_ttf:\t%d.%d.%d", + SDL_TTF_MAJOR_VERSION, + SDL_TTF_MINOR_VERSION, + SDL_TTF_PATCHLEVEL); +#if VILE_FEATURE_FLUIDSYNTH + LogMessage("\tFluidsynth:\t%d.%d.%d", + FLUIDSYNTH_VERSION_MAJOR, + FLUIDSYNTH_VERSION_MINOR, + FLUIDSYNTH_VERSION_MICRO); +#endif +#if VILE_FEATURE_FFMPEG + LogMessage("\tavcodec:\t%d.%d.%d", + LIBAVCODEC_VERSION_MAJOR, + LIBAVCODEC_VERSION_MINOR, + LIBAVCODEC_VERSION_MICRO); + LogMessage("\tavformat:\t%d.%d.%d", + LIBAVFORMAT_VERSION_MAJOR, + LIBAVFORMAT_VERSION_MINOR, + LIBAVFORMAT_VERSION_MICRO); + LogMessage("\tswscale:\t%d.%d.%d", + LIBSWSCALE_VERSION_MAJOR, + LIBSWSCALE_VERSION_MINOR, + LIBSWSCALE_VERSION_MICRO); +#endif + LogMessage(""); +} + +bool ViLE::Archive(uString Archive,Stringlist *List){ + Resources resman; + int count=List->GetCount(); + for(int i=0;iGetString(i)); + } + return resman.Write(Archive); +} + +bool ViLE::Decode(uString InFile){ + bool retval=false; + Resources resman; + resman.AddResource(InFile); + SDL_Surface *image=resman.GetImage(InFile); + SDL_Surface **animation=resman.GetAnimation(InFile); + uString OutFile=EDL_FileDirectory(InFile)+EDL_FileName(InFile)+".bmp"; + if(animation){ + char buffer[OutFile.length()+10]; + LogMessage("Converting animation resource to bitmaps: %s -> %s", + InFile.c_str(),OutFile.c_str()); + for(int i=0;animation[i];i++){ + sprintf(buffer,"%s_%02d.bmp",OutFile.c_str(),i+1); + SDL_SaveBMP(animation[i],buffer); + SDL_FreeSurface(animation[i]); + retval=true; + } + delete [] animation; + } + else if(image){ + LogMessage("Converting image resource to bitmap: %s -> %s", + InFile.c_str(),OutFile.c_str()); + SDL_SaveBMP(image,OutFile.c_str()); + SDL_FreeSurface(image); + retval=true; + } + else{ + LogMessage("Not a decodable resource: %s",InFile.c_str()); + } + return retval; +} + +/*! \brief Lists resources in a game archive + * \param Archive Archive to list + * \return True if any resources where found + */ +bool ViLE::List(uString Archive){ + bool retval=false; + Resources resman; + if(resman.AddResource(Archive)>0){ + Stringlist list; + int c=resman.EnumerateResources(&list); + retval=c>0; + for(int i=0;i0){ + Stringlist list; + int c=resman.EnumerateResources(&list); + retval=c>0; + for(int i=0;iSeek(0,SEEK_END); + int size=res->Tell(); + if(size>0){ + Uint8 *buffer=new Uint8[size]; + res->Seek(0,SEEK_SET); + res->Read(buffer,size); + FILE *output=fopen(name.c_str(),"wb"); + if(output){ + LogMessage("Writing %d bytes to %s", + size,name.c_str()); + fwrite(buffer,1,size,output); + fclose(output); + retval=true; + } + else{ + LogError("Could not write target: %s", + name.c_str()); + } + delete [] buffer; + } + } + } + } + else{ + LogError("Not a valid archive: %s",Archive.c_str()); + } + return retval; +} + +/*! \brief Extracts a resource from a game archive + * \param Archive Archive to extract from + * \param List Resources to extract + * \return True if output file was successfully written + */ +bool ViLE::Extract(uString Archive,Stringlist *List){ + bool retval=false; + Resources resman; + if(List && resman.AddResource(Archive)>0){ + int c=List->GetCount(); + for(int i=0;iGetString(i); + RWops *res=resman.GetResource(name); + if(res){ + res->Seek(0,SEEK_END); + int size=res->Tell(); + if(size>0){ + Uint8 *buffer=new Uint8[size]; + res->Seek(0,SEEK_SET); + res->Read(buffer,size); + FILE *output=fopen(name.c_str(),"wb"); + if(output){ + LogMessage("Writing %d bytes to %s", + size,name.c_str()); + fwrite(buffer,1,size,output); + fclose(output); + retval=true; + } + else{ + LogError("Could not write target: %s", + name.c_str()); + } + delete [] buffer; + } + } + else{ + LogMessage("Invalid resource: %s",name.c_str()); + } + } + } + else{ + LogError("Not a valid archive: %s",Archive.c_str()); + } + return retval; +} + +/*! \brief Extracts AND decodes resources from an archive + * \param Archive Archive to extract from + * \return True if any resources where found + */ +bool ViLE::XDec(uString Archive){ + bool retval=false; + Resources resman; + if(resman.AddResource(Archive)>0){ + Stringlist list; + int c=resman.EnumerateResources(&list); + retval=c>0; + for(int i=0;iSeek(0,SEEK_END); + int size=res->Tell(); + if(size>0){ + Uint8 *buffer=new Uint8[size]; + res->Seek(0,SEEK_SET); + res->Read(buffer,size); + delete res; + FILE *output=fopen(name.c_str(),"wb"); + if(output){ + LogMessage("Writing %d bytes to %s", + size,name.c_str()); + fwrite(buffer,1,size,output); + fclose(output); + retval=true; + } + else{ + LogError("Could not write target: %s", + name.c_str()); + } + delete [] buffer; + } + } + } + } + else{ + LogError("Not a valid archive: %s",Archive.c_str()); + } + return retval; +} + +/*! \brief Extracts AND decodes resources from an archive + * \param Archive Archive to extract from + * \param List Resources to extract + * \return True if any resources where found + */ +bool ViLE::XDec(uString Archive,Stringlist *List){ + bool retval=false; + Resources resman; + if(List && resman.AddResource(Archive)>0){ + int c=List->GetCount(); + for(int i=0;iGetString(i); + SDL_Surface **animation; + SDL_Surface *image; + RWops *res; + if((animation=resman.GetAnimation(name))){ + LogMessage("Converting animation to frames: %s",name.c_str()); + for(int i=0;animation[i];i++){ + if(i==0 && animation[1]==0){ + sprintf(buffer,"%s.bmp",name.c_str()); + } + else{ + sprintf(buffer,"%s_%02d.bmp",name.c_str(),i+1); + } + SDL_SaveBMP(animation[i],buffer); + SDL_FreeSurface(animation[i]); + retval=true; + } + delete [] animation; + } + else if((image=resman.GetImage(name))){ + LogTest("Converting %s to bitmap",name.c_str()); + name+=".bmp"; + SDL_SaveBMP(image,name.c_str()); + SDL_FreeSurface(image); + retval=true; + } + else if((res=resman.GetResource(name))){ + res->Seek(0,SEEK_END); + int size=res->Tell(); + if(size>0){ + Uint8 *buffer=new Uint8[size]; + res->Seek(0,SEEK_SET); + res->Read(buffer,size); + delete res; + FILE *output=fopen(name.c_str(),"wb"); + if(output){ + LogMessage("Writing %d bytes to %s", + size,name.c_str()); + fwrite(buffer,1,size,output); + fclose(output); + retval=true; + } + else{ + LogError("Could not write target: %s", + name.c_str()); + } + delete [] buffer; + } + } + } + } + else{ + LogError("Not a valid archive: %s",Archive.c_str()); + } + return retval; +} + +void ViLE::Error(uString Title,uString Message){ + // Report failed loading + EngineVN *evn=new EngineVN(640,480); + while(evn->DestroyAnimation()); + Widget *widget=new Widget(0,0,640,480); + widget->Fill(0xFFFFFFFF); + Fatal *fatal=new Fatal(evn,Title,Message); + evn->DestroyLayer(VL_DIALOG); + evn->AddWidget(widget,VL_BACKGROUND); + evn->AddWidget(fatal,VL_DIALOG); + RunEngine(evn); +} + + diff --git a/engines/vileVN/vile.h b/engines/vileVN/vile.h new file mode 100644 index 0000000000..60c71b2719 --- /dev/null +++ b/engines/vileVN/vile.h @@ -0,0 +1,103 @@ +#ifndef _VILE_H_ +#define _VILE_H_ + +// Include systemstuff +#include "engine/evn.h" + +// Include games +#ifdef VILE_SUPPORT_CROWD +#include "crowd/tokimeki/tokimeki.h" +#include "crowd/xchange1/xchange1.h" +#include "crowd/xchange3/xchange3.h" +#endif +#ifdef VILE_SUPPORT_IKURA +#include "ikura/crescendo/crescendo.h" +#include "ikura/sagara/sagara.h" +#include "ikura/snow/snow.h" +#include "ikura/kana/kana.h" +#include "ikura/kanaoka/kanaoka.h" +#include "ikura/hitomi/hitomi.h" +#include "ikura/catgirl/catgirl.h" +#include "ikura/idols/idols.h" +#endif +#ifdef VILE_SUPPORT_WINDY +#include "windy/mayclub/mayclub.h" +#include "windy/nocturnal/nocturnal.h" +#endif +#ifdef VILE_SUPPORT_JAST +#include "jast/jumc.h" +#endif +#ifdef VILE_SUPPORT_CWARE +#include "cware/dividead/dividead.h" +#endif +#ifdef VILE_SUPPORT_WILL +#include "will/yume/yume.h" +#include "will/critical/critical.h" +#endif +#ifdef VILE_SUPPORT_TLOVE +#include "tlove/tlove.h" +#endif + +// Default window size +#define DEFAULT_WIDTH 640 +#define DEFAULT_HEIGHT 480 + + +// Application error codes +#define ERROR_NONE 0 +#define ERROR_PARAMETER 10 +#define ERROR_INITSYSTEM 20 +#define ERROR_INITVIDEO 30 +#define ERROR_INITGAME 40 + +class ViLE { + private: + // Probers + bool ProbeNocturnal(uString Path); + bool ProbeDiviDead(uString Path); + bool ProbeMayclub(uString Path); + bool ProbeCrescendo(uString Path); + bool ProbeSagara(uString Path); + bool ProbeSnow(uString Path); + bool ProbeYumeMiruKusuri(uString Path); + bool ProbeCriticalPoint(uString Path); + bool ProbeTrueLove(uString Path); + bool ProbeKanaOkaeri(uString Path); + bool ProbeKana(uString Path); + bool ProbeHitomi(uString Path); + bool ProbeCatGirl(uString Path); + bool ProbeIdols(uString Path); + bool ProbeJUMC(uString Path); + bool ProbeTokimeki(uString Path); + bool ProbeXChange1(uString Path); + bool ProbeXChange3(uString Path); + + // Probing methods + bool ProbeSUF(uString Path,uString Key); + bool ProbeResource(uString Path,uString Resource); + bool ProbeString(uString S1,uString S2); + bool ProbeSize(uString Path,unsigned int Size); + public: + EngineVN *LoadEngine(uString Path); + void RunEngine(EngineVN *Engine); + bool InitSystem(Uint32 Flags); + bool InitVideo(); + void Quit(); + + void About(); + void Help(); + void InfoRuntime(); + void InfoTitle(EngineVN *Engine); + void InfoResources(EngineVN *Engine); + bool List(uString Archive); + bool Archive(uString Archive,Stringlist *List); + bool XDec(uString Archive); + bool XDec(uString Archive,Stringlist *List); + bool Extract(uString Archive); + bool Extract(uString Archive,Stringlist *List); + bool Decode(uString Resource); + void Error(uString Title,uString Message); +}; + +#endif + diff --git a/engines/vileVN/widgets/animation.cpp b/engines/vileVN/widgets/animation.cpp new file mode 100644 index 0000000000..fb0985c0b1 --- /dev/null +++ b/engines/vileVN/widgets/animation.cpp @@ -0,0 +1,49 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "animation.h" + +Animation::Animation(int X,int Y,int Width,int Height) + : Widget(X,Y,Width,Height){ + fhittable=true; +} + +Animation::Animation(SDL_Rect Dst) : Widget(Dst){ + fhittable=true; +} + +Animation::Animation() : Widget(){ + fhittable=true; +} + +/*! \brief Tells wether animation should continue + * \return True if animation is running + */ +bool Animation::Continue(){ + return false; +} + +/*! \brief Skips or completes current animations + * \returns True if an animation was skipped + * + * The base implementation of this method will skip the current animation + * and move onto the next, derivated animation widgets will finish what its + * doing. + */ +bool Animation::Skip(){ + return false; +} + + diff --git a/engines/vileVN/widgets/animation.h b/engines/vileVN/widgets/animation.h new file mode 100644 index 0000000000..be10cd2154 --- /dev/null +++ b/engines/vileVN/widgets/animation.h @@ -0,0 +1,20 @@ +/*! \class Animation + * \brief Defines an animated widget + */ +#ifndef _ANIMATION_H_ +#define _ANIMATION_H_ + +#include "widget.h" + +class Animation : public Widget { + public: + Animation(int X,int Y,int Width,int Height); + Animation(SDL_Rect Dst); + Animation(); + + // Interact with dynamic objects + virtual bool Continue(); + virtual bool Skip(); +}; + +#endif diff --git a/engines/vileVN/widgets/bbutton.cpp b/engines/vileVN/widgets/bbutton.cpp new file mode 100644 index 0000000000..01fb48bceb --- /dev/null +++ b/engines/vileVN/widgets/bbutton.cpp @@ -0,0 +1,214 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "bbutton.h" + +BitmapButton::BitmapButton() : StateWidget(){ + fhittable=true; + state=WS_NORMAL; + for(int i=0;iw/3,(bmp->h/2)/3}; + SDL_Rect nd={0,0,bmp->w/3,(bmp->h/2)/3}; + SDL_Rect hs={0,bmp->h/2,bmp->w/3,(bmp->h/2)/3}; + SDL_Rect hd={0,0,bmp->w/3,(bmp->h/2)/3}; + + EDL_BlitSurface(bmp,&ns,nsurface,&nd); + EDL_BlitSurface(bmp,&hs,hsurface,&hd); + ns.x+=ns.w; + hs.x+=hs.w; + while(nd.x+nd.ww-ns.w; + hs.x=bmp->w-hs.w; + nd.x=pos.w-nd.w; + hd.x=pos.w-hd.w; + EDL_BlitSurface(bmp,&ns,nsurface,&nd); + EDL_BlitSurface(bmp,&hs,hsurface,&hd); + + // Create middle + EDL_SETRECT(ns,0,ns.y+ns.h,ns.w,ns.h); + EDL_SETRECT(hs,0,hs.y+hs.h,hs.w,hs.h); + EDL_SETRECT(nd,0,nd.y+nd.h,nd.w,nd.h); + EDL_SETRECT(hd,0,hd.y+hd.h,hd.w,hd.h); + EDL_BlitSurface(bmp,&ns,nsurface,&nd); + EDL_BlitSurface(bmp,&hs,hsurface,&hd); + ns.x+=ns.w; + hs.x+=hs.w; + while(nd.x+nd.ww-ns.w; + hs.x=bmp->w-hs.w; + nd.x=pos.w-nd.w; + hd.x=pos.w-hd.w; + EDL_BlitSurface(bmp,&ns,nsurface,&nd); + EDL_BlitSurface(bmp,&hs,hsurface,&hd); + + // Duplicate middle + SDL_Rect ts={0,ns.h,pos.w,ns.h}; + SDL_Rect td=ts; + while(td.y+td.hh/2)-ns.h,ns.w,ns.h); + EDL_SETRECT(hs,0,bmp->h-hs.h,hs.w,hs.h); + EDL_SETRECT(nd,0,pos.h-nd.h,nd.w,nd.h); + EDL_SETRECT(hd,0,pos.h-hd.h,hd.w,hd.h); + EDL_BlitSurface(bmp,&ns,nsurface,&nd); + EDL_BlitSurface(bmp,&hs,hsurface,&hd); + ns.x+=ns.w; + hs.x+=hs.w; + while(nd.x+nd.ww-ns.w; + hs.x=bmp->w-hs.w; + nd.x=pos.w-nd.w; + hd.x=pos.w-hd.w; + EDL_BlitSurface(bmp,&ns,nsurface,&nd); + EDL_BlitSurface(bmp,&hs,hsurface,&hd); + + + // Create caption + SDL_Surface *txt=EDL_CreateText(String, + Cfg::Color::WidgetFont, + nsurface->w-bmp->w, + EDL_MIN(nsurface->h,Cfg::Font::default_size)); + if(txt){ + SDL_Rect d={0,0,txt->w,txt->h}; + if(txt->ww){ + d.x=(nsurface->w-txt->w)/2; + } + if(txt->hh){ + d.y=(nsurface->h-txt->h)/2; + } + EDL_BlendSurface(txt,0,nsurface,&d); + EDL_BlendSurface(txt,0,hsurface,&d); + SDL_FreeSurface(txt); + } + SetState(WS_NORMAL,nsurface,0); + SetState(WS_HOVER,hsurface,0); + SDL_FreeSurface(bmp); + } + SDL_FreeSurface(nsurface); + SDL_FreeSurface(hsurface); +} + +/*! \brief Sets graphics for a specific state + * \param State Which set of graphics to use + * \param Src Source surface + * \param X X coordinate + * \param Y Y coordinate + * \param W Width + * \param H Height + */ +void BitmapButton::SetState(int State,SDL_Surface *Src,int X,int Y,int W,int H){ + SDL_Rect trect={X,Y,W,H}; + SetState(State,Src,&trect); +} + +/*! \brief Sets graphics for a specific state + * \param State Which set of graphics to use + * \param Src Source surface + * \param SRect Part of source to copy + */ +void BitmapButton::SetState(int State,SDL_Surface *Src,SDL_Rect *SRect){ + if(Statew,SRect->h); + } + else{ + surfaces[State]=EDL_CreateSurface(GetWidth(),GetHeight()); + } + + // Copy graphics + EDL_BlitSurface(Src,SRect,surfaces[State],0); + if(State==state){ + Blit(surfaces[State]); + } + } +} + diff --git a/engines/vileVN/widgets/bbutton.h b/engines/vileVN/widgets/bbutton.h new file mode 100644 index 0000000000..978eab9d81 --- /dev/null +++ b/engines/vileVN/widgets/bbutton.h @@ -0,0 +1,31 @@ +/*! \class BitmapButton + * \brief You run-of-the-mill button-type object + */ +#ifndef _BBUTTON_H_ +#define _BBUTTON_H_ + +#include "swidget.h" + +class BitmapButton : public StateWidget { + private: + SDL_Surface *surfaces[WIDGET_STATE_SIZE]; + int state; + public: + BitmapButton(SDL_Rect Position); + BitmapButton(int X,int Y,int Widht,int Height); + BitmapButton(); + ~BitmapButton(); + + // For setting custom graphics + void SetState(int State,SDL_Surface *Src,SDL_Rect *SRect); + void SetState(int State,SDL_Surface *Src,int X,int Y,int W,int H); + + // Autogeneration + void SetCaption(uString String); + + // Overrides + virtual void ChangeState(WIDGET_STATE State); +}; + +#endif + diff --git a/engines/vileVN/widgets/checkbox.cpp b/engines/vileVN/widgets/checkbox.cpp new file mode 100644 index 0000000000..1f78916ae3 --- /dev/null +++ b/engines/vileVN/widgets/checkbox.cpp @@ -0,0 +1,101 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "checkbox.h" + +Checkbox::Checkbox(SDL_Rect Pos,uString Caption,bool Leftsided) + : ValueButton(Pos) { + leftsided=Leftsided; + caption=Caption; + autogenerate(); +} + +Checkbox::Checkbox(uString Caption,bool Leftsided) : ValueButton() { + leftsided=Leftsided; + caption=Caption; + autogenerate(); +} + +void Checkbox::SetOrientation(bool Leftsided){ + leftsided=Leftsided; + autogenerate(); +} + +void Checkbox::SetCaption(uString Caption){ + caption=Caption; + autogenerate(); +} + +void Checkbox::autogenerate(){ + SDL_Surface *nssurface=EDL_CreateSurface(pos.w,pos.h); + SDL_Surface *nusurface=EDL_CreateSurface(pos.w,pos.h); + SDL_Surface *hssurface=EDL_CreateSurface(pos.w,pos.h); + SDL_Surface *husurface=EDL_CreateSurface(pos.w,pos.h); + SDL_Surface *bmp=Media::GetImage("checkbox"); + if(bmp){ + SDL_Surface *txt=EDL_CreateText(caption, + Cfg::Color::WidgetFont, + nssurface->w-bmp->w,nssurface->h); + if(txt){ + SDL_Rect d={bmp->w*1.25,0,txt->w,txt->h}; + if(!leftsided){ + d.x=0; + } + if(txt->hh)/2; + } + EDL_BlitSurface(txt,0,nssurface,&d); + EDL_BlitSurface(txt,0,nusurface,&d); + EDL_BlitSurface(txt,0,hssurface,&d); + EDL_BlitSurface(txt,0,husurface,&d); + SDL_FreeSurface(txt); + } + SDL_Rect s={0,0,bmp->w,bmp->h/4}; + SDL_Rect d={0,0,bmp->w,bmp->h/4}; + if(s.h=start+duration){ + // Fade is complete ... + EDL_SetAlpha(sfade,0,0xFF); + Blit(sfade); + SDL_FreeSurface(sfade); + sfade=0; + Widget::Copy(Dst); + } + else{ + // Calculate a new fade step based upon time + double p=(now-start)/(double)duration; + p=255-(EDL_HANNING(p,2)*255); + //SDL_SetAlpha(sfade,SDL_SRCALPHA,(Uint8)EDL_LIMIT(p,0x00,0xFF)); + //EDL_BlitSurface(sfade,0,Dst,&crect); + EDL_SetAlpha(sfade,0,(Uint8)EDL_LIMIT(p,0x00,0xFF)); + EDL_BlendSurface(sfade,0,Dst,&crect); + Refresh(); + } +} + + diff --git a/engines/vileVN/widgets/fade.h b/engines/vileVN/widgets/fade.h new file mode 100644 index 0000000000..059649f519 --- /dev/null +++ b/engines/vileVN/widgets/fade.h @@ -0,0 +1,47 @@ +/*! \class Fade + * \brief Fade animation widget + */ +#ifndef _FADE_H_ +#define _FADE_H_ + +#include "animation.h" +#include + +class Fade : public Animation { + private: + // Common + SDL_Surface *sfade; //!< Surface to fade or whatever into + Uint32 start; //!< Time the effect started + Uint32 duration; //!< How long the effect should run + SDL_Rect crect; //!< Rect relative to widget + public: + Fade(SDL_Rect Dst); + Fade(SDL_Rect Dst,SDL_Surface *Surface, + SDL_Rect Rect,Uint32 Duration); + ~Fade(); + void SetFade(SDL_Surface *Surface,SDL_Rect Rect,Uint32 Duration); + void Copy(SDL_Surface *Dst); + bool Skip(); + bool Continue(); +}; + +class FadeBlack : public Fade { + public: + FadeBlack(SDL_Rect Dst,Uint32 Duration); + +}; + +class FadeWhite : public Fade { + public: + FadeWhite(SDL_Rect Dst,Uint32 Duration); + +}; + +class FadeColor : public Fade { + public: + FadeColor(SDL_Rect Dst,SDL_Color Color,Uint32 Duration); + FadeColor(SDL_Rect Dst,Uint8 R,Uint8 G,Uint8 B,Uint32 Duration); +}; + +#endif + diff --git a/engines/vileVN/widgets/group.cpp b/engines/vileVN/widgets/group.cpp new file mode 100644 index 0000000000..230b5b4d2c --- /dev/null +++ b/engines/vileVN/widgets/group.cpp @@ -0,0 +1,372 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "group.h" + +Widget *Group::widget_bin=0; + +/*! \brief Creates a new Group object + * \param Parent Parent group + * \int Position Logical position (Group) to set for the group + * + * If a parent object is provided, the group will add itself to the parent + * group automatically. This asserts that newly created groups are ordered + * on the intended stack. + */ +Group::Group(Group *Parent,int Position){ + // Set defaults + parent=Parent; + widget_focus=widget_top=widget_bottom=0; + group_top=group_bottom=0; + NextPtr=PrevPtr=0; + widgetcount=0; + groupcount=0; + + if(parent){ + // Automatically assign to parent + parent->AddGroup(this,Position); + } +} + +Group::~Group(){ + DestroyGroup(); +} + +/*! \brief Removes all widgets from the stack + */ +void Group::DropGroup(){ + // Drop all children groups + if(!parent){ + groupcount=0; + Group *gptr=group_top; + group_top=group_bottom=0; + while(gptr){ + Group *tmpptr=gptr->NextPtr; + gptr=tmpptr; + } + } + + // Drop children widgets + widgetcount=0; + Widget *wptr=widget_top; + widget_top=widget_bottom=0; + while(wptr){ + Widget *tmpptr=wptr->NextPtr; + wptr=tmpptr; + } +} + +/*! \brief Destroys all assigned objects in the group + * + * If the object is a parent object it will destroy any assigned groups, + * otherwise it will just destroy assigned objects. + */ +void Group::DestroyGroup(){ + // Destroy all children groups + if(!parent){ + groupcount=0; + Group *gptr=group_top; + group_top=group_bottom=0; + while(gptr){ + Group *tmpptr=gptr->NextPtr; + delete gptr; + gptr=tmpptr; + } + } + + // Destroy children widgets + widgetcount=0; + Widget *wptr=widget_top; + widget_top=widget_bottom=0; + while(wptr){ + // Backup pointer and schedule object for deletion + Widget *tmpptr=wptr->NextPtr; + wptr->NextPtr=widget_bin; + widget_bin=wptr; + wptr=tmpptr; + } +} + + +/*! \brief Destroys a widget and removes it from the group + * \param Widget Widget to destroy and remove + * + * The object is not actually destroyed, but moved to a different stack + * were it will continue to exist until Purge() is called. + */ +void Group::DestroyWidget(Widget *WidgetPtr){ + if(WidgetPtr){ + if(DropWidget(WidgetPtr)){ + // Schedule object for deletion + if(widget_bin){ + WidgetPtr->NextPtr=widget_bin; + widget_bin=WidgetPtr->NextPtr; + } + else{ + WidgetPtr->NextPtr=0; + widget_bin=WidgetPtr; + } + } + } +} + + +/*! \brief Deletes previously removed/destroyed items + */ +void Group::Purge(){ + while(widget_bin){ + Widget *tmpptr=widget_bin; + widget_bin=widget_bin->NextPtr; + delete tmpptr; + } +} + +/*! \brief Counts assigned groups + * \returns Assigned groups + * + * This will only work for parent objects! + */ +int Group::GetGroupCount(){ + return groupcount; +} + +/*! \brief Counts assigned widgets + * \returns Assigned widgets + * + * This is not recursive, assigned groups will not be checked + */ +int Group::GetWidgetCount(){ + return widgetcount; +} + +/*! \brief Fetches an indexed group + * \returns Indexed group or NULL if out of range + */ +Group *Group::GetGroup(int Position){ + Group *retval=group_top; + if(parent){ + retval=parent->group_top; + } + for(int i=1;retval && i<=Position;i++){ + retval=retval->NextPtr; + } + return retval; +} + +bool Group::CheckWidget(Widget *WidgetPtr){ + bool returnval=false; + if(WidgetPtr){ + // Search own widgets + Widget *wptr=widget_top; + while(wptr && wptr!=WidgetPtr){ + wptr=wptr->NextPtr; + } + returnval=wptr; + + // Search child group widgets + Group *gptr=group_top; + while(!returnval && gptr){ + returnval=gptr->CheckWidget(WidgetPtr); + gptr=gptr->NextPtr; + } + } + return returnval; +} + +/*! \brief Fetches an indexed widget + * \param Position The index of the widget you want + * \returns Indexed group or NULL if out of range + */ +Widget *Group::GetWidget(int Position){ + Widget *retval=widget_top; + for(int i=1;retval && i<=Position;i++){ + retval=retval->NextPtr; + } + return retval; +} + +/*! \brief Fetches first widget at given position + * \param X Screen coordinate + * \param Y Screen coordinate + * \returns Indexed group or NULL if out of range + */ +Widget *Group::GetWidget(int X,int Y){ + Widget *retval=widget_top; + while(retval){ + if(retval->TestMouse(X,Y)){ + break; + } + retval=retval->NextPtr; + } + return retval; +} + +void Group::AddGroup(Group *GroupPtr,int Position){ + if(GroupPtr){ + if(!group_top){ + // First object! + group_top=group_bottom=GroupPtr; + GroupPtr->PrevPtr=0; + GroupPtr->NextPtr=0; + } + else{ + if(!Position){ + // Top position + GroupPtr->PrevPtr=0; + GroupPtr->NextPtr=group_top; + group_top->PrevPtr=GroupPtr; + group_top=GroupPtr; + } + else if(Position>=groupcount){ + // Bottom position + GroupPtr->PrevPtr=group_bottom; + GroupPtr->NextPtr=0; + group_bottom->NextPtr=GroupPtr; + group_bottom=GroupPtr; + } + else{ + // Seek out a position + Group *tmpptr; + tmpptr=group_top; + for(int i=0;tmpptr->NextPtr && iNextPtr; + } + + // Inject widget + GroupPtr->NextPtr=tmpptr->NextPtr; + GroupPtr->PrevPtr=tmpptr->PrevPtr; + tmpptr->PrevPtr=GroupPtr; + tmpptr->NextPtr=GroupPtr; + } + } + groupcount++; + } +} + +/*! \brief Removes a widget from the stack + * \returns True if widget was found and removed + */ +bool Group::DropWidget(Widget *WidgetPtr){ + bool retval=false; + if(!WidgetPtr){ + // This is futile ... + } + else if(WidgetPtr==widget_top){ + // Drop top item + retval=true; + if(widget_bottom==WidgetPtr){ + widget_top=0; + widget_bottom=0; + widgetcount=0; + } + else{ + widget_top=widget_top->NextPtr; + widget_top->PrevPtr=0; + widgetcount--; + } + } + else if(WidgetPtr==widget_bottom){ + // Drop bottom item + widget_bottom=widget_bottom->PrevPtr; + widget_bottom->NextPtr=0; + widgetcount--; + retval=true; + } + else{ + // Untangle from stack + Widget *tmpptr=widget_top; + while(tmpptr){ + if(tmpptr->NextPtr==WidgetPtr){ + // Found item + widgetcount--; + tmpptr->NextPtr=WidgetPtr->NextPtr; + if(tmpptr->NextPtr){ + tmpptr->NextPtr->PrevPtr=tmpptr; + } + WidgetPtr->NextPtr=0; + WidgetPtr->PrevPtr=0; + retval=true; + break; + } + tmpptr=tmpptr->NextPtr; + } + } + return retval; +} + +/*! \brief Inverse the direction of widgets (Top=bottom, bottom=top) + */ +void Group::FlipWidgets(){ + Group *tmpgroup=new Group(0); + int oldcnt=widgetcount; + for(int i=0;iAddWidget(tmpwidget,i); + } +} + +void Group::AddWidget(Widget *WidgetPtr,int Position){ + if(WidgetPtr){ + if(!widget_top){ + // First object! + widget_top=widget_bottom=WidgetPtr; + WidgetPtr->PrevPtr=0; + WidgetPtr->NextPtr=0; + } + else{ + if(!Position){ + // Top position + WidgetPtr->PrevPtr=0; + WidgetPtr->NextPtr=widget_top; + widget_top->PrevPtr=WidgetPtr; + widget_top=WidgetPtr; + } + else if(Position>=widgetcount || Position<0){ + // Bottom position + WidgetPtr->PrevPtr=widget_bottom; + WidgetPtr->NextPtr=0; + widget_bottom->NextPtr=WidgetPtr; + widget_bottom=WidgetPtr; + } + else{ + // Seek out a position + Widget *tmpptr=widget_top; + for(int i=0;tmpptr->NextPtr && iNextPtr; + } + + // Inject widget + WidgetPtr->NextPtr=tmpptr->NextPtr; + WidgetPtr->PrevPtr=tmpptr->PrevPtr; + tmpptr->PrevPtr=WidgetPtr; + tmpptr->NextPtr=WidgetPtr; + } + } + + // Count widgets as they are added + WidgetPtr->Refresh(); + widgetcount++; + } +} + +void Group::MoveWidget(Widget *WidgetPtr,int Position){ + if(WidgetPtr){ + if(DropWidget(WidgetPtr)){ + AddWidget(WidgetPtr,Position); + } + } +} + diff --git a/engines/vileVN/widgets/group.h b/engines/vileVN/widgets/group.h new file mode 100644 index 0000000000..6a686c383d --- /dev/null +++ b/engines/vileVN/widgets/group.h @@ -0,0 +1,66 @@ +/*! \class Group + * \brief Groups widgets into logical layers + * + * The group object manages a collection of widgets and/or other groups, but + * does not handle events or input focus type of things (See DialogBase for + * dialog handling). It merely clusters widgets together (usually) into + * so-called layers. + * + * The Group class is also responsible for safely destroying client widgets + * using the Purge() mechanism. + * + * The stack is bidirectional and can be visualized like this: + * + * LAST FIRST + * 0<-TOP->Next ... Prev<-BOTTOM->0 + */ +#ifndef _GROUP_H_ +#define _GROUP_H_ + +#include "widget.h" + +class Group { + private: + static Widget *widget_bin; //!< Objects scheduled for destruction + Group *group_top; //!< Top group (for parents only) + Group *group_bottom; //!< Bottom group (for parents only) + Group *parent; //!< Parent group (Null for parent) + Widget *widget_top; //!< Top widget of THIS group + Widget *widget_bottom; //!< Bottom widget of THIS group + Widget *widget_focus; //!< Holds current focus + int widgetcount; //!< Widgets attached to THIS group + int groupcount; //!< Groups attached to this group + public: + Group(Group *Parent,int Position=0); + ~Group(); + int GetGroupCount(); + int GetWidgetCount(); + Group *GetGroup(int Position); + Widget *GetWidgetByTag(int Tag); + Widget *GetWidget(int Position); + Widget *GetWidget(int X,int Y); + void AddGroup(Group *GroupPtr,int Position=0); + void MoveGroup(Group *GroupPtr,int Position); + void DropGroup(Group *GroupPtr); + void FlipWidgets(); + void AddWidget(Widget *WidgetPtr,int Position=0); + void MoveWidget(Widget *WidgetPtr,int Position); + bool CheckWidget(Widget *WidgetPtr); + bool DropWidget(Widget *WidgetPtr); + + // Removes objects from their stacks + void DestroyWidget(Widget *WidgetPtr); + void DestroyGroup(); + void DropGroup(); + + // Deletes removed objects + static void Purge(); + + // Navigation pointers + Group *PrevPtr; + Group *NextPtr; +}; + +#endif + + diff --git a/engines/vileVN/widgets/hotspot.cpp b/engines/vileVN/widgets/hotspot.cpp new file mode 100644 index 0000000000..c4aad4c8e4 --- /dev/null +++ b/engines/vileVN/widgets/hotspot.cpp @@ -0,0 +1,29 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "hotspot.h" + +Hotspot::Hotspot(int X,int Y,int Width,int Height) : Widget(X,Y,Width,Height){ + fhittable=true; +} + +Hotspot::Hotspot(SDL_Rect Dst) : Widget(Dst){ + fhittable=true; +} + +Hotspot::Hotspot() : Widget(){ + fhittable=true; +} + diff --git a/engines/vileVN/widgets/hotspot.h b/engines/vileVN/widgets/hotspot.h new file mode 100644 index 0000000000..cdf1042810 --- /dev/null +++ b/engines/vileVN/widgets/hotspot.h @@ -0,0 +1,16 @@ +/*! \class Hotspot + * \brief Defines an on-screen field that takes input + */ +#ifndef _HOTSPOT_H_ +#define _HOTSPOT_H_ + +#include "widget.h" + +class Hotspot : public Widget { + public: + Hotspot(int X,int Y,int Width,int Height); + Hotspot(SDL_Rect Dst); + Hotspot(); +}; + +#endif diff --git a/engines/vileVN/widgets/mwidget.cpp b/engines/vileVN/widgets/mwidget.cpp new file mode 100644 index 0000000000..27570d95fe --- /dev/null +++ b/engines/vileVN/widgets/mwidget.cpp @@ -0,0 +1,49 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "mwidget.h" +#include "../engine/evn.h" + +MusicWidget::MusicWidget(EngineVN *Engine,RWops *Music) : Animation() { + engine=Engine; + music=Music; +} + +bool MusicWidget::Continue(){ + return music; +} + +bool MusicWidget::Skip(){ + bool retval=music; + if(music){ + if(engine){ + engine->PlayMusic(music); + } + delete music; + music=0; + } + return retval; +} + +void MusicWidget::Copy(SDL_Surface *Dst){ + if(music){ + if(engine){ + engine->PlayMusic(music); + } + delete music; + music=0; + } +} + diff --git a/engines/vileVN/widgets/mwidget.h b/engines/vileVN/widgets/mwidget.h new file mode 100644 index 0000000000..7dc2b482c8 --- /dev/null +++ b/engines/vileVN/widgets/mwidget.h @@ -0,0 +1,30 @@ +/*! \class MusicWidget + * \brief Defines a non-graphical widget that starts a music track + * + * This widget allows queing a video resource in the blitting queue, hence + * allowing it to execute as part of a sequence of animations or videos. + * + * Usually used through the EngineVN::QueueMusic() convenience functions + */ +#ifndef _MUSICWIDGET_H_ +#define _MUSICWIDGET_H_ + +#include "animation.h" + +class EngineVN; + +class MusicWidget : public Animation { + private: + // Overrides + virtual void Copy(SDL_Surface *Dst); + virtual bool Continue(); + virtual bool Skip(); + + // The actual payload + EngineVN *engine; + RWops *music; + public: + MusicWidget(EngineVN *Engine,RWops *Music); +}; + +#endif diff --git a/engines/vileVN/widgets/printer.cpp b/engines/vileVN/widgets/printer.cpp new file mode 100644 index 0000000000..ed132a27e6 --- /dev/null +++ b/engines/vileVN/widgets/printer.cpp @@ -0,0 +1,476 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "printer.h" + +Printer::Printer(int X,int Y,int Width,int Height) : Widget(X,Y,Width,Height){ + // Preset values + stext=0; + index=0; + interval=50; + charcount=0; + wordwrap=true; + clearscreen=false; + + // Create default font + font_ttf=0; + font_size=Cfg::Font::default_size; + font_style=Cfg::Font::default_style; + SetBackgroundColor(0x00000000); + SetFontColor(0xFFFFFFFF); + SetFontFace(Cfg::Font::default_face.c_str()); +} + +Printer::Printer(SDL_Rect Pos) : Widget(Pos){ + // Preset values + stext=0; + index=0; + interval=50; + charcount=0; + wordwrap=true; + clearscreen=false; + + // Create default font + font_ttf=0; + font_size=Cfg::Font::default_size; + font_style=Cfg::Font::default_style; + SetBackgroundColor(0x00000000); + SetFontColor(0xFFFFFFFF); + SetFontFace(Cfg::Font::default_face.c_str()); +} + +Printer::Printer() : Widget(){ + // Preset values + stext=0; + index=0; + interval=50; + charcount=0; + wordwrap=true; + clearscreen=false; + + // Create default font + font_ttf=0; + font_size=Cfg::Font::default_size; + font_style=Cfg::Font::default_style; + SetBackgroundColor(0x00000000); + SetFontColor(0xFFFFFFFF); + SetFontFace(Cfg::Font::default_face.c_str()); +} + +Printer::~Printer(){ + if(stext){ + SDL_FreeSurface(stext); + } + if(font_ttf){ + TTF_CloseFont(font_ttf); + } +} + +void Printer::SetWordwrap(bool Enable){ + wordwrap=Enable; +} + +void Printer::SetFontFace(uString Name){ + // Verify font existence + if(Name.length() && Name!=font_name){ + FILE *tf=fopen(Name.c_str(),"r"); + if(tf){ + fclose(tf); + font_name=Name; + if(font_ttf){ + TTF_CloseFont(font_ttf); + } + font_ttf=TTF_OpenFont(font_name.c_str(),font_size); + if(!font_ttf){ + LogError("Failed to open font: %s",font_name.c_str()); + } + } + else{ + LogError("Failed to find font: %s",font_name.c_str()); + } + } +} + +void Printer::SetFontSize(int Size){ + // Register new size + font_size=Size; + + // Attempt to recreate font + if(font_name.length()){ + if(font_ttf){ + TTF_CloseFont(font_ttf); + } + font_ttf=TTF_OpenFont(font_name.c_str(),font_size); + } +} + +void Printer::SetBackgroundColor(Uint32 Color){ + back_color.r=(Color>>24)&0xFF; + back_color.g=(Color>>16)&0xFF; + back_color.b=(Color>>8)&0xFF; + back_alpha=Color&0xFF; +} + +void Printer::SetFontColor(Uint32 Color){ + font_color.r=(Color>>24)&0xFF; + font_color.g=(Color>>16)&0xFF; + font_color.b=(Color>>8)&0xFF; +} + +void Printer::SetFontColor(Uint8 Red,Uint8 Green,Uint8 Blue){ + font_color.r=Red; + font_color.g=Green; + font_color.b=Blue; +} + +void Printer::SetFontColor(SDL_Color Color){ + font_color.r=Color.r; + font_color.g=Color.g; + font_color.b=Color.b; +} + +void Printer::SetFontStyle(int Style){ + font_style=Style; + if(font_ttf){ + TTF_SetFontStyle(font_ttf,font_style); + } +} + +void Printer::SetFontShadow(int X,int Y,SDL_Color Color){ + LogMessage("SETFONTSHADOW"); +} + +void Printer::SetFontGlow(int Glow,SDL_Color Color){ + LogMessage("SETFONTGLOW"); +} + +/*! \brief Prints remaining text immidiatly + * \return True if text was rendered + */ +bool Printer::Skip(){ + bool retval=font_ttf && text.length(); + if(retval){ + while(text.length()){ + while(printnext()); + } + Refresh(); + } + return retval; +} + +/*! \brief Prints remaining text immidiatly, but wait at full display + * \return True if text was rendered + */ +bool Printer::SkipScreen(){ + bool retval=text.length(); + if(retval){ + if(clearscreen){ + clearscreen=false; + ClearScreen(); + start=SDL_GetTicks(); + } + while(printnext()); + Refresh(); + } + return retval; +} + + +/*! \brief Tells wether animation should continue + * \return True if animation is running + */ +bool Printer::Continue(){ + return text.length(); +} + +/*! \brief Clear text and display + */ +void Printer::Clear(){ + if(stext){ + SDL_FreeSurface(stext); + stext=0; + Refresh(); + } + index=0; + text=""; + curtext=""; + charcount=0; +} + +/*! \brief Clear display only + */ +void Printer::ClearScreen(){ + if(stext){ + // Drop printed text + SDL_FreeSurface(stext); + stext=0; + Refresh(); + } + if(text.length()>index){ + // Clear currently printed text + start=SDL_GetTicks(); + text=text.substr(index); + index=0; + } + else{ + // Clear all text + text=""; + index=0; + } + curtext=""; + charcount=0; + trect.y=0; + trect.x=0; +} + +/*! \brief Total number of characters to be printed + * \returns Total number of characters to be printed + */ +int Printer::GetLength(){ + return charcount; +} + +/*! \brief Number of characters not yet printed + * \returns Number of characters not yet printed + */ +int Printer::GetRemaining(){ + return EDL_MAX(text.length()-index,0); +} + +int Printer::GetInterval(){ + return interval; +} + +void Printer::SetInterval(Uint32 Interval){ + interval=Interval; +} + +void Printer::Newline(){ + if(font_ttf){ + if(text.length()){ + text+="\n"; + } + else{ + int w,h; + if(!TTF_SizeText(font_ttf,"A",&w,&h)){ + trect.x=0; + trect.y+=h; + } + } + Refresh(); + } +} + +void Printer::Reprint(int Interval){ + // Complete current text + Skip(); + + // Start over + start=SDL_GetTicks(); + uString curtextb=curtext; + Clear(); + text=curtextb; + curtext=""; + index=0; + + // Append textlength and override interval + charcount+=text.length(); + if(Interval>=0){ + interval=Interval; + } + Refresh(); + +} + +/*! \brief Prints text (Appended to existing) + * \param Text Text to be printed + * \param Interval Delay between each character (-1=Use preset value) + */ +void Printer::Print(uString Text,int Interval){ + if(text.length()){ + // Append to existing text + text+=Text; + } + else{ + // Prepare printing data + start=SDL_GetTicks(); + text=Text; + index=0; + } + + // Append textlength and override interval + charcount+=Text.length(); + if(Interval>=0){ + interval=Interval; + } + Refresh(); +} + +void Printer::Autosize(uString Text){ + if(font_ttf){ + int width,height; + if(!TTF_SizeText(font_ttf,Text.c_str(),&width,&height)){ + Resize(width,height); + } + } +} + +bool Printer::GetTextSize(uString Text,int *Width,int *Height){ + bool retval=false; + if(font_ttf){ + retval=!TTF_SizeText(font_ttf,Text.c_str(),Width,Height); + } + return retval; +} + +/*! \brief Prints next character to the internal surface + * \returns True if text was added + */ +bool Printer::printnext(){ + bool retval=false; + if(font_ttf && text.length()){ + // Assert a 32bit RGBA surface for transparent text + if(!stext){ + stext=EDL_CreateSurface(pos.w,pos.w); + trect.x=0; + trect.y=0; + } + + // Check for special characters + while(indexpos.w){ + // Wrap text and drop whitespace + trect.x=0; + trect.y+=h; + index++; + } + } + } + + // Check for vertical wordwrap + if(wordwrap && indexpos.h){ + clearscreen=true; + return false; + } + } + } + + // Get next character + if(indexstart+(interval*index) && + (refresh=printnext())); + } + else{ + while(text.length() && (refresh=printnext())); + } + + // Force refresh until all text has been printed + Refresh(); + } + if(simage){ + // Use widget graphics + Widget::Copy(Dst); + } + if(stext){ + // Blend in transparant text + SDL_Rect tpos=pos; + EDL_BlendSurface(stext,0,Dst,&tpos); + } + } +} + + diff --git a/engines/vileVN/widgets/printer.h b/engines/vileVN/widgets/printer.h new file mode 100644 index 0000000000..39a761a18c --- /dev/null +++ b/engines/vileVN/widgets/printer.h @@ -0,0 +1,65 @@ +/*! \class Printer + * \brief Widget for printing text + */ +#ifndef _PRINTER_H_ +#define _PRINTER_H_ + +#include "widget.h" + +class Printer : public Widget { + private: + TTF_Font *font_ttf; + SDL_Color font_color; + SDL_Color back_color; + unsigned char back_alpha; + uString font_name; + int font_size; + int font_style; + SDL_Surface *stext; //!< Surface for current textview + uString text; //!< Text to print + uString curtext; //!< Text that has been printed + unsigned int index; //!< Current text index + Uint32 interval; //!< Milliseconds per character + Uint32 start; //!< Start of sequence + SDL_Rect crect; //!< Client rect relative to widget + SDL_Rect trect; //!< Current print position + int charcount; //!< Number of printed characters + bool wordwrap; //!< Wether or not to wrap text lines + bool clearscreen; //!< Clear screen at next pass (wordwrap only) + bool printnext(); + public: + Printer(int X,int Y,int Width,int Height); + Printer(SDL_Rect Position); + Printer(); + ~Printer(); + void Autosize(uString Text); + int GetLength(); + int GetRemaining(); + int GetInterval(); + void SetInterval(Uint32 Interval); + void Reprint(int Interval=-1); + void Print(uString Text,int Interval=-1); + void Newline(); + bool Skip(); + bool SkipScreen(); + bool Continue(); + void Clear(); + void ClearScreen(); + void SetWordwrap(bool Enable); + void SetBackgroundColor(Uint32 Color); + void SetFontFace(uString Filename); + void SetFontSize(int Size); + void SetFontColor(Uint8 Red,Uint8 Green,Uint8 Blue); + void SetFontColor(SDL_Color Color); + void SetFontColor(Uint32 Color); + void SetFontStyle(int Style); + void SetFontShadow(int X,int Y,SDL_Color Color); + void SetFontGlow(int Glow,SDL_Color Color); + bool GetTextSize(uString Text,int *Width,int *Height); + + // Api for external printing + void Copy(SDL_Surface *Dst); +}; + +#endif + diff --git a/engines/vileVN/widgets/saveslab.cpp b/engines/vileVN/widgets/saveslab.cpp new file mode 100644 index 0000000000..261652b6f2 --- /dev/null +++ b/engines/vileVN/widgets/saveslab.cpp @@ -0,0 +1,222 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "saveslab.h" + +SaveSlab::SaveSlab(int X,int Y,int Width,int Height) : Widget(X,Y,Width,Height){ + // Unset surfaces + sbackground=0; + soverlay=0; + sthumb=0; + sdate=0; + stext=0; + + // Set defaults + selected=false; + fhittable=true; +} + +SaveSlab::SaveSlab(SDL_Rect Position) : Widget(Position){ + // Unset surfaces + sbackground=0; + soverlay=0; + sthumb=0; + sdate=0; + stext=0; + + // Set defaults + selected=false; + fhittable=true; +} + +SaveSlab::~SaveSlab(){ + Flush(); +} + +void SaveSlab::Flush(){ + if(sbackground){ + SDL_FreeSurface(sbackground); + sbackground=0; + } + if(soverlay){ + SDL_FreeSurface(soverlay); + soverlay=0; + } + if(sthumb){ + SDL_FreeSurface(sthumb); + sthumb=0; + } + if(sdate){ + SDL_FreeSurface(sdate); + sdate=0; + } + if(stext){ + SDL_FreeSurface(stext); + stext=0; + } +} + +void SaveSlab::update(){ + if(sbackground){ + Blit(sbackground); + if(sthumb){ + Blend(sthumb,0,&rthumb); + } + if(stext){ + Blend(stext,0,&rtext); + } + } + else{ + if(sthumb){ + Blit(sthumb,0,&rthumb); + } + if(stext){ + Blit(stext,0,&rtext); + } + } + + if(selected && soverlay){ + Blend(soverlay); + } +} + +void SaveSlab::SetSelected(bool Selected){ + if(Selected!=selected){ + selected=Selected; + update(); + } +} + +/*! \brief Forces a value on the backgrounds alpha channel + */ +void SaveSlab::SetBackgroundAlpha(Uint8 Alpha){ + if(sbackground){ + EDL_SetAlpha(sbackground,0,Alpha); + update(); + } +} + +/*! \brief Sets widget background + * \param Src Source graphics + * \param SRect Source rectangle + */ +void SaveSlab::SetBackground(SDL_Surface *Src,SDL_Rect *SRect){ + if(Src){ + SDL_Rect srect={0,0,Src->w,Src->h}; + if(SRect){ + srect.x=SRect->x; + srect.y=SRect->y; + srect.w=SRect->w; + srect.h=SRect->h; + } + if(sbackground){ + SDL_FreeSurface(sbackground); + } + sbackground=EDL_CreateSurface(srect.w,srect.h); + EDL_BlitSurface(Src,&srect,sbackground,0); + update(); + } +} + +/*! \brief Sets graphics to be blended in when widget is selected + * \param Src Source graphics + * \param SRect Source rectangle + */ +void SaveSlab::SetOverlay(SDL_Surface *Src,SDL_Rect *SRect){ + if(Src){ + SDL_Rect srect={0,0,Src->w,Src->h}; + if(SRect){ + srect.x=SRect->x; + srect.y=SRect->y; + srect.w=SRect->w; + srect.h=SRect->h; + } + if(soverlay){ + SDL_FreeSurface(soverlay); + } + + soverlay=EDL_CreateSurface(srect.w,srect.h); + EDL_BlitSurface(Src,&srect,soverlay,0); + update(); + } +} + +/*! \brief Explicitly sets the thumbnail graphics + * \param Src Source graphics + * \param SRect Source rectangle + * \param DRect Destination rectangle + */ +void SaveSlab::SetThumb(SDL_Surface *Src,SDL_Rect *SRect,SDL_Rect *DRect){ + if(Src){ + // Register destination + if(DRect){ + rthumb.x=DRect->x; + rthumb.y=DRect->y; + rthumb.w=DRect->w; + rthumb.h=DRect->h; + } + else{ + rthumb.x=0; + rthumb.y=0; + rthumb.w=Src->w; + rthumb.h=Src->h; + } + + // Create graphics + if(sthumb){ + SDL_FreeSurface(sthumb); + } + sthumb=EDL_CreateSurface(rthumb.w,rthumb.h); + EDL_BlitSurface(Src,SRect,sthumb,0); + update(); + } + +} + +void SaveSlab::SetDate(Uint64 Unixtime,SDL_Rect *DRect){ +} + +void SaveSlab::SetText(uString Message,SDL_Rect *DRect){ + if(Message.length()){ + // Register destination + if(DRect){ + rtext.x=DRect->x; + rtext.y=DRect->y; + rtext.w=DRect->w; + rtext.h=DRect->h; + } + else if(stext){ + rtext.x=0; + rtext.y=0; + rtext.w=stext->w; + rtext.h=stext->h; + } + else{ + rtext.x=0; + rtext.y=0; + rtext.w=pos.w; + rtext.h=pos.h; + } + + if(stext){ + SDL_FreeSurface(stext); + } + stext=EDL_CreateMultilineText(Message,0xFF0000FF,rtext.w,rtext.h); + + // Update graphics + update(); + } +} + diff --git a/engines/vileVN/widgets/saveslab.h b/engines/vileVN/widgets/saveslab.h new file mode 100644 index 0000000000..4e2e4e5093 --- /dev/null +++ b/engines/vileVN/widgets/saveslab.h @@ -0,0 +1,38 @@ +/*! \class SaveSlab + * \brief Widget for displaying a load- or savegame + */ +#ifndef _SAVESLAB_H_ +#define _SAVESLAB_H_ + +#include "widget.h" +#include "printer.h" +#include "../common/savegame.h" + +class SaveSlab : public Widget { + private: + SDL_Surface *sbackground; //!< Background surface + SDL_Surface *soverlay; //!< Overlay surface + SDL_Surface *sthumb; //!< Thumbnail surface + SDL_Surface *sdate; //!< Date surface + SDL_Surface *stext; //!< Text surface + SDL_Rect rthumb; //!< Thumbnail position + SDL_Rect rdate; //!< Date position + SDL_Rect rtext; //!< Text position + bool selected; + void update(); + public: + SaveSlab(int X,int Y,int Width,int Height); + SaveSlab(SDL_Rect Position); + ~SaveSlab(); + void SetSelected(bool Selected); + void SetBackground(SDL_Surface *Src,SDL_Rect *SRect); + void SetBackgroundAlpha(Uint8 Alpha); + void SetOverlay(SDL_Surface *Src,SDL_Rect *SRect); + void SetThumb(SDL_Surface *Src,SDL_Rect *SRect,SDL_Rect *DRect); + void SetDate(Uint64 Unixtime,SDL_Rect *DRect); + void SetText(uString Message,SDL_Rect *DRect); + void Flush(); +}; + +#endif + diff --git a/engines/vileVN/widgets/scroll.cpp b/engines/vileVN/widgets/scroll.cpp new file mode 100644 index 0000000000..d8e0865e58 --- /dev/null +++ b/engines/vileVN/widgets/scroll.cpp @@ -0,0 +1,122 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "scroll.h" + +Scroll::Scroll(SDL_Rect Dst,SDL_Surface *Source,SDL_Rect Start,SDL_Rect End, + Uint32 Duration) : Animation(Dst) { + // Set default values + start=0; + duration=0; + surface=0; + Animate(Source,Start,End,Duration); +} + + +Scroll::Scroll(SDL_Rect Dst) : Animation(Dst) { + // Set default values + start=0; + duration=0; + surface=0; +} + +Scroll::Scroll() : Animation() { + // Set default values + start=0; + duration=0; + surface=0; +} + +Scroll::~Scroll(){ + if(surface){ + SDL_FreeSurface(surface); + } +} + +/*! \brief Completes the running fade effect + * + * The finished graphics are copied to the primary widget surface + * and the animation surface is deleted. Subsequent calls to Copy() + * will use the widget graphics as source. + */ +bool Scroll::Skip(){ + bool retval=surface; + if(surface){ + Blit(surface,&rdest); + SDL_FreeSurface(surface); + surface=0; + duration=0; + start=0; + } + return retval; +} + +/*! \brief Tells wether animation should continue + * \return True if animation is running + */ +bool Scroll::Continue(){ + return surface; +} + +void Scroll::Animate(SDL_Surface *Src,SDL_Rect Start,SDL_Rect End,Uint32 Time){ + // Prepare + start=0; + duration=Time; + rstart=Start; + rdest=End; + if(surface){ + SDL_FreeSurface(surface); + } + + // Create surface and build graphics + surface=EDL_CopySurface(Src,0); + + // Assert redraw + Refresh(); +} + +/*! \brief Copies graphics + * \param Dst Target surface + */ +void Scroll::Copy(SDL_Surface *Dst){ + if(!start && surface){ + // Start effect + start=SDL_GetTicks(); + } + else if(surface){ + Uint32 now=SDL_GetTicks(); + if(now>start && now-startstart && now-starth/4)*0,bmp->w,bmp->h/4}; + SDL_Rect nu={0,(bmp->h/4)*2,bmp->w,bmp->h/4}; + SDL_Rect hs={0,(bmp->h/4)*1,bmp->w,bmp->h/4}; + SDL_Rect hu={0,(bmp->h/4)*3,bmp->w,bmp->h/4}; + SetGraphics(WS_NORMAL,bmp,&ns,bmp,&nu); + SetGraphics(WS_HOVER,bmp,&hs,bmp,&hu); + SDL_FreeSurface(bmp); + } +} + +Slider::~Slider(){ + for(int i=0;ipos.x){ + SetValue(((X-pos.x)/(double)pos.w)*100); + } + return true; +} + +bool Slider::MouseLeftDown(int X,int Y){ + focus=true; + SetValue(((X-pos.x)/(double)pos.w)*100); + return StateWidget::MouseLeftDown(X,Y); +} + +bool Slider::MouseLeftUp(int X,int Y){ + focus=false; + return StateWidget::MouseLeftUp(X,Y); +} + +int Slider::GetValue(){ + return value; +} + +void Slider::SetValue(int Value){ + if(value!=Value && Value>=0 && Value<=100){ + value=Value; + AutoGenerate(); + } +} + +void Slider::AutoGenerate(){ + if(state0 && pos.h>0){ + // Get positions + int xval=(pos.w*GetValue())/100; + SDL_Surface *surface=EDL_CreateSurface(pos.w,pos.h); + SDL_Rect rsrc={0,0,full[state]->w/2,full[state]->h}; + SDL_Rect rdst={0,0,full[state]->w/2,full[state]->h}; + if(pos.h>full[state]->h){ + rdst.y=(pos.h-full[state]->h)/2; + } + rsrc.w=EDL_LIMIT(rsrc.w,2,4); + rdst.w=EDL_LIMIT(rdst.w,2,4); + + // Paint middle section + rdst.x=rdst.w; + rsrc.x=full[state]->w/3; + while(rdst.xrdst.x){ + SDL_Rect tsrc=rsrc; + SDL_Rect tdst=rdst; + tdst.w=xval-rdst.x; + tsrc.w=tdst.w; + EDL_BlitSurface(full[state],&tsrc,surface,&tdst); + rdst.x+=tdst.w; + } + while(rdst.x0){ + EDL_BlitSurface(full[state],&rsrc,surface,&rdst); + } + else{ + EDL_BlitSurface(empty[state],&rsrc,surface,&rdst); + } + rdst.x=pos.w-rdst.w; + rsrc.x=full[state]->w-rsrc.w; + if(xvalrdst.x){ + EDL_BlitSurface(full[state],&rsrc,surface,&rdst); + } + + // Update widget graphic + Blit(surface); + SDL_FreeSurface(surface); + Refresh(); + } +} + +void Slider::SetGraphics(WIDGET_STATE State, + SDL_Surface *SFull,SDL_Rect *RFull, + SDL_Surface *SEmpty,SDL_Rect *REmpty){ + if(Statew,SFull->h}; + if(RFull){ + r=*RFull; + } + full[State]=EDL_CreateSurface(r.w,r.h); + EDL_BlitSurface(SFull,&r,full[State],0); + + // Set empty graphics + if(empty[State]){ + SDL_FreeSurface(empty[State]); + } + if(empty[State]){ + SDL_FreeSurface(empty[State]); + } + EDL_SETRECT(r,0,0,SEmpty->w,SEmpty->h); + if(REmpty){ + r=*REmpty; + } + empty[State]=EDL_CreateSurface(r.w,r.h); + EDL_BlitSurface(SEmpty,&r,empty[State],0); + + // Recreate graphics + if(State==state){ + AutoGenerate(); + } + } +} + + diff --git a/engines/vileVN/widgets/slider.h b/engines/vileVN/widgets/slider.h new file mode 100644 index 0000000000..bf2e87df9d --- /dev/null +++ b/engines/vileVN/widgets/slider.h @@ -0,0 +1,35 @@ +/*! \class Slider + * \brief Allows the user to set a numeric value in a range + */ +#ifndef _SLIDER_H_ +#define _SLIDER_H_ + +#include "swidget.h" + +class Slider : public StateWidget { + private: + SDL_Surface *full[WIDGET_STATE_SIZE]; + SDL_Surface *empty[WIDGET_STATE_SIZE]; + bool focus; + int value; + public: + Slider(SDL_Rect Position); + ~Slider(); + + // Slider API + void SetGraphics(WIDGET_STATE State, + SDL_Surface *SFull,SDL_Rect *RFull, + SDL_Surface *SEmpty,SDL_Rect *REmpty); + void AutoGenerate(); + void SetValue(int Value); + int GetValue(); + + // Overrides + virtual void ChangeState(WIDGET_STATE State); + virtual bool MouseMove(int X,int Y); + virtual bool MouseLeftDown(int X,int Y); + virtual bool MouseLeftUp(int X,int Y); +}; + +#endif + diff --git a/engines/vileVN/widgets/sprite.cpp b/engines/vileVN/widgets/sprite.cpp new file mode 100644 index 0000000000..a09bb62e35 --- /dev/null +++ b/engines/vileVN/widgets/sprite.cpp @@ -0,0 +1,106 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "sprite.h" + +Sprite::Sprite(SDL_Rect Dst) : Widget(Dst) { + start=SDL_GetTicks(); + spritestack=0; + spritecur=0; + fhittable=false; +} + +Sprite::Sprite() : Widget() { + start=SDL_GetTicks(); + spritestack=0; + spritecur=0; + fhittable=false; +} + +Sprite::~Sprite(){ + ClearFrames(); +} + +void Sprite::ClearFrames(){ + spritecur=0; + while(spritestack){ + SPRITEFRAME *tmpptr=spritestack->NextPtr; + SDL_FreeSurface(spritestack->Surface); + delete spritestack; + spritestack=tmpptr; + } +} + +void Sprite::AddFrame(SDL_Surface *Surface,SDL_Rect *Src,Uint32 Duration){ + // Add a new frame to the stackpointer + SPRITEFRAME *tmpptr=spritestack; + if(tmpptr){ + while(tmpptr->NextPtr){ + tmpptr=tmpptr->NextPtr; + } + tmpptr->NextPtr=new SPRITEFRAME; + tmpptr=tmpptr->NextPtr; + } + else{ + spritestack=new SPRITEFRAME; + tmpptr=spritestack; + } + + // Populate sprite + tmpptr->Surface=EDL_CopySurface(Surface,Src); + tmpptr->Duration=Duration; + tmpptr->NextPtr=0; + + // Assert sprite + if(!spritecur){ + spritecur=spritestack; + } +} + +/*! \brief Triggers refreshes in order to advance the animation + */ +void Sprite::Tick(){ + if(spritestack){ + Uint32 now=SDL_GetTicks(); + if(now=spritecur->Duration){ + Refresh(); + } + } +} + +/*! \brief Copies graphics + * \param Dst Target surface + */ +void Sprite::Copy(SDL_Surface *Dst){ + if(Dst && spritestack){ + // Change frame + Uint32 now=SDL_GetTicks(); + if(now=spritecur->Duration){ + start=now; + if(spritecur->NextPtr){ + spritecur=spritecur->NextPtr; + } + else{ + spritecur=spritestack; + } + } + + // Copy frame + SDL_Rect lpos={0,0,pos.w,pos.h}; + EDL_BlendSurface(spritecur->Surface,&lpos,Dst,&pos); + } +} + + diff --git a/engines/vileVN/widgets/sprite.h b/engines/vileVN/widgets/sprite.h new file mode 100644 index 0000000000..007ee7f35a --- /dev/null +++ b/engines/vileVN/widgets/sprite.h @@ -0,0 +1,31 @@ +/*! \class Sprite + * \brief Animated sprite + * + * The sprite can only animate at low framerate as it uses the bulky + * widget-tick event to drive itself. Consider an highspeed option on + * demand. + */ +#ifndef _SPRITE_H_ +#define _SPRITE_H_ + +#include "widget.h" + +class Sprite : public Widget { + private: + struct SPRITEFRAME { + SDL_Surface *Surface; + Uint32 Duration; + SPRITEFRAME *NextPtr; + }*spritestack,*spritecur; + Uint32 start; + public: + Sprite(SDL_Rect Dst); + Sprite(); + ~Sprite(); + void AddFrame(SDL_Surface *Surface,SDL_Rect *Src,Uint32 Duration); + void ClearFrames(); + virtual void Tick(); + virtual void Copy(SDL_Surface *Dst); +}; + +#endif diff --git a/engines/vileVN/widgets/swidget.cpp b/engines/vileVN/widgets/swidget.cpp new file mode 100644 index 0000000000..d71c7ae77d --- /dev/null +++ b/engines/vileVN/widgets/swidget.cpp @@ -0,0 +1,81 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "swidget.h" + +StateWidget::StateWidget() : Widget(){ + state=WS_NORMAL; +} + +StateWidget::StateWidget(SDL_Rect Pos) : Widget(Pos){ + state=WS_NORMAL; +} + +StateWidget::StateWidget(int X,int Y,int W,int H) : Widget(X,Y,W,H){ + state=WS_NORMAL; +} + +void StateWidget::ChangeState(WIDGET_STATE State){ + if(Statew,txt->h}; + if(horizontal==HA_CENTER){ + td.x=(pos.w-txt->w)/2; + } + if(horizontal==HA_RIGHT){ + td.x=pos.w-txt->w; + } + if(vertical==VA_CENTER){ + td.y=(pos.h-txt->h)/2; + } + if(vertical==VA_BOTTOM){ + td.y=pos.h-txt->h; + } + SDL_Surface *surface=EDL_CreateSurface(pos.w,pos.h); + if(colorbg[state]&0xFF){ + Uint8 r=(colorbg[state]>>24)&0xFF; + Uint8 g=(colorbg[state]>>16)&0xFF; + Uint8 b=(colorbg[state]>>8)&0xFF; + Uint8 a=colorbg[state]&0xFF; + boxRGBA(surface,0,0,pos.w,pos.h,r,g,b,a); + EDL_BlendSurface(txt,0,surface,&td); + } + else{ + EDL_BlitSurface(txt,0,surface,&td); + } + Refresh(); + Set(surface); + SDL_FreeSurface(surface); + SDL_FreeSurface(txt); + } + } +} + diff --git a/engines/vileVN/widgets/tbutton.h b/engines/vileVN/widgets/tbutton.h new file mode 100644 index 0000000000..abcd5f9149 --- /dev/null +++ b/engines/vileVN/widgets/tbutton.h @@ -0,0 +1,58 @@ +/*! \class TextButton + * \brief A input sensitive text control with optional background + */ +#ifndef _TBUTTON_H +#define _TBUTTON_H + +#include "swidget.h" + +#define TEXT_LEFT 0 +#define TEXT_CENTER 1 +#define TEXT_RIGHT 2 +#define TA + +enum HALIGN { + HA_LEFT=0, + HA_CENTER, + HA_RIGHT +}; + +enum VALIGN { + VA_TOP=0, + VA_CENTER, + VA_BOTTOM +}; + +class TextButton : public StateWidget { + private: + Uint32 colorfg[WIDGET_STATE_SIZE]; + Uint32 colorbg[WIDGET_STATE_SIZE]; + HALIGN horizontal; + VALIGN vertical; + uString caption; + int fontsize; + void autogenerate(); + public: + TextButton(int X,int Y,uString Caption); + TextButton(int X,int Y,int Width,int Height,uString Caption); + TextButton(SDL_Rect Dst,uString Caption); + TextButton(SDL_Rect Dst); + TextButton(); + + // Configuration + virtual void SetAlignment(HALIGN Horizontal,VALIGN Vertical); + virtual void SetFontSize(int Size); + + // Color schema + virtual Uint32 GetColorBackground(WIDGET_STATE State); + virtual Uint32 GetColorForeground(WIDGET_STATE State); + virtual void SetColorBackground(WIDGET_STATE State,Uint32 Color); + virtual void SetColorForeground(WIDGET_STATE State,Uint32 Color); + virtual void SetColorDefault(); + + // Overrides + virtual void ChangeState(WIDGET_STATE State); + virtual void Resize(int Width,int Height); +}; + +#endif diff --git a/engines/vileVN/widgets/vbutton.cpp b/engines/vileVN/widgets/vbutton.cpp new file mode 100644 index 0000000000..957d0b228e --- /dev/null +++ b/engines/vileVN/widgets/vbutton.cpp @@ -0,0 +1,143 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "vbutton.h" + +ValueButton::ValueButton() : StateWidget(){ + fhittable=true; + value=false; + for(int i=0;iw,SRect->h); + } + else{ + ssurfaces[State]=EDL_CreateSurface(GetWidth(),GetHeight()); + } + + // Copy graphics + EDL_BlitSurface(SSurface,SRect,ssurfaces[State],0); + } + if(Statew,URect->h); + } + else{ + usurfaces[State]=EDL_CreateSurface(GetWidth(),GetHeight()); + } + + // Copy graphics + EDL_BlitSurface(USurface,URect,usurfaces[State],0); + } + + // Update widget graphics + if(State==state){ + if(value){ + if(ssurfaces[state]){ + Blit(ssurfaces[state]); + } + } + else{ + if(usurfaces[state]){ + Blit(usurfaces[state]); + } + } + } + +} + diff --git a/engines/vileVN/widgets/vbutton.h b/engines/vileVN/widgets/vbutton.h new file mode 100644 index 0000000000..f0c4ff52c8 --- /dev/null +++ b/engines/vileVN/widgets/vbutton.h @@ -0,0 +1,32 @@ +/*! \class ValueButton + * \brief Widget with state graphics + */ +#ifndef _VBUTTON_H_ +#define _VBUTTON_H_ + +#include "swidget.h" + +class ValueButton : public StateWidget { + private: + SDL_Surface *ssurfaces[WIDGET_STATE_SIZE]; + SDL_Surface *usurfaces[WIDGET_STATE_SIZE]; + bool value; + public: + ValueButton(SDL_Rect Position); + ValueButton(); + ~ValueButton(); + void SetState(int State, + SDL_Surface *SSurface,SDL_Rect *SRect, + SDL_Surface *USurface,SDL_Rect *URect); + void SetState(int State, + SDL_Surface *SSurface,int SX,int SY,int SW,int SH, + SDL_Surface *USurface,int UX,int UY,int UW,int UH); + void SetValue(bool Value); + bool GetValue(); + + // Overrides + virtual void ChangeState(WIDGET_STATE State); +}; + +#endif + diff --git a/engines/vileVN/widgets/vwidget.cpp b/engines/vileVN/widgets/vwidget.cpp new file mode 100644 index 0000000000..c6c964045a --- /dev/null +++ b/engines/vileVN/widgets/vwidget.cpp @@ -0,0 +1,49 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "vwidget.h" +#include "../engine/evn.h" + +VideoWidget::VideoWidget(EngineVN *Engine,RWops *Video) : Animation() { + engine=Engine; + video=Video; +} + +bool VideoWidget::Continue(){ + return video; +} + +bool VideoWidget::Skip(){ + bool retval=video; + if(video){ + if(engine){ + engine->PlayVideo(video); + } + delete video; + video=0; + } + return retval; +} + +void VideoWidget::Copy(SDL_Surface *Dst){ + if(video){ + if(engine){ + engine->PlayVideo(video); + } + delete video; + video=0; + } +} + diff --git a/engines/vileVN/widgets/vwidget.h b/engines/vileVN/widgets/vwidget.h new file mode 100644 index 0000000000..efe086a922 --- /dev/null +++ b/engines/vileVN/widgets/vwidget.h @@ -0,0 +1,31 @@ +/*! \class VideoWidget + * \brief Defines a non-graphical widget that starts a video + * + * This widget allows queing a video resource in the blitting queue, hence + * allowing it to execute as part of a sequence of animations or other + * videos. + * + * Usually used through the EngineVN::QueueVideo() convenience functions + */ +#ifndef _VIDEOWIDGET_H_ +#define _VIDEOWIDGET_H_ + +#include "animation.h" + +class EngineVN; + +class VideoWidget : public Animation { + private: + // Overrides + virtual void Copy(SDL_Surface *Dst); + virtual bool Continue(); + virtual bool Skip(); + + // The actual payload + EngineVN *engine; + RWops *video; + public: + VideoWidget(EngineVN *Engine,RWops *Video); +}; + +#endif diff --git a/engines/vileVN/widgets/widget.cpp b/engines/vileVN/widgets/widget.cpp new file mode 100644 index 0000000000..a45a3f8b91 --- /dev/null +++ b/engines/vileVN/widgets/widget.cpp @@ -0,0 +1,539 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "widget.h" +#include "group.h" + +bool Widget::global_refresh=false; +SDL_Rect Widget::global_update={0,0,0,0}; + +Widget::Widget(int X,int Y,int Width,int Height){ + setdefaults(); + pos.x=X; + pos.y=Y; + pos.w=Width; + pos.h=Height; +} + +Widget::Widget(SDL_Rect Position){ + setdefaults(); + pos=Position; +} + +Widget::Widget(){ + // Preset values + setdefaults(); +} + +Widget::~Widget(){ + Free(); +} + +/*! \brief Helper to initialise object values across constructors + */ +void Widget::setdefaults(){ + // Preset values + PrevPtr=NextPtr=0; + simage=0; + tag=0; + pos.x=0; + pos.y=0; + pos.h=0; + pos.w=0; + fhittable=false; + fvisible=true; + local_refresh=false; + local_update.x=0; + local_update.y=0; + local_update.w=0; + local_update.h=0; +} + +/*! \brief Gets refresh data without resetting them + * \param Cliprect Gets populated with update rect + * \return True if display needs refresh + */ +bool Widget::PeekGlobalRefresh(SDL_Rect *Cliprect){ + if(global_refresh && Cliprect){ + *Cliprect=global_update; + } + return global_refresh; +} + +/*! \brief Gets refresh data and then resets them + * \param Cliprect Gets populated with update rect + * \return True if display needs refresh + */ +bool Widget::GetGlobalRefresh(SDL_Rect *Cliprect){ + bool retval=global_refresh; + if(global_refresh && Cliprect){ + *Cliprect=global_update; + } + global_update.x=0; + global_update.y=0; + global_update.w=0; + global_update.h=0; + global_refresh=false; + return retval; +} + +/*! \brief Gets widget refresh data + * \param Cliprect Gets populated with update rect + * \return True if widget needs refresh + */ +bool Widget::PeekLocalRefresh(SDL_Rect *Cliprect){ + if(local_refresh && Cliprect){ + *Cliprect=local_update; + } + return local_refresh; +} + +/*! \brief Gets widget refresh data and then resets them + * \param Cliprect Gets populated with update rect + * \return True if widget needs refresh + */ +bool Widget::GetLocalRefresh(SDL_Rect *Cliprect){ + bool retval=local_refresh; + if(local_refresh && Cliprect){ + *Cliprect=local_update; + } + local_update.x=0; + local_update.y=0; + local_update.w=0; + local_update.h=0; + local_refresh=false; + return retval; +} + +/*! \brief Flags system for graphic refresh + * \param Update Rectangle to update + */ +void Widget::Refresh(SDL_Rect *Update){ + // Set flags and assert update rect + global_refresh=true; + local_refresh=true; + if(!Update){ + Update=&pos; + } + + // Update rects + if(!global_update.w && !global_update.h){ + // Update entire rect + global_update=*Update; + } + else{ + // Grow global rect to cover Update + global_update=EDL_AddRect(global_update,*Update); + } + + if(!local_update.w && !local_update.h){ + local_update=*Update; + } + else{ + // Grow local rect to cover Update + local_update=EDL_AddRect(local_update,*Update); + } +} + +/*! \brief Forces screen redraw + */ +void Widget::Redraw(){ + SDL_Surface *video=SDL_GetVideoSurface(); + global_refresh=true; + global_update.x=0; + global_update.y=0; + global_update.w=video->w; + global_update.h=video->h; +} + +/*! \brief Sets a tag value + * \param Tag New tag value + * + * Tags do not have any generic meaning; They are a free-form field that + * other parts of the engine use to assign data or identify a widget in a + * group of widgets. + */ +void Widget::SetTag(Uint32 Tag){ + tag=Tag; +} + +/*! \brief Reads tag value + * \returns Read tag value + */ +Uint32 Widget::GetTag(){ + return tag; +} + +/*! \brief Moves and resizes the widget on the screen + * \param Position New onscreen position for widget + */ +void Widget::Move(SDL_Rect Position){ + Move(Position.x,Position.y); + Resize(Position.w,Position.h); +} + +/*! \brief Moves widget on the screen + * \param X X coordinate + * \param Y Y coordinate + */ +void Widget::Move(int X,int Y){ + if(pos.x!=X || pos.y!=Y){ + pos.x=X; + pos.y=Y; + Refresh(); + } +} + +/*! \brief Resizes widget on the screen + * \param Position New onscreen position for widget + */ +void Widget::Resize(int W,int H){ + if(pos.w!=W || pos.h!=H){ + pos.w=W; + pos.h=H; + Refresh(); + } +} + +/*! \brief Tells X position of the widget + * \returns X position (Relative to native size) + */ +int Widget::GetX(){ + return pos.x; +} + +/*! \brief Tells Y position of the widget + * \returns Y position (Relative to native size) + */ +int Widget::GetY(){ + return pos.y; +} + +/*! \brief Tells the width of the widget + * \returns Widget width position (Relative to native size) + */ +int Widget::GetWidth(){ + return pos.w; +} + +/*! \brief Tells the height of the widget + * \returns Widget height (Relative to native size) + */ +int Widget::GetHeight(){ + return pos.h; +} + +/*! \brief Tells the position of the widget + * \returns Widget position rect (Relative to native size) + */ +SDL_Rect Widget::GetPosition(){ + return pos; +} + +void Widget::Free(){ + if(simage){ + SDL_FreeSurface(simage); + simage=0; + Refresh(); + } +} + +/*! \brief Sets widget alpha level + * \param Alpha Alphalevel (0=Transparent, 255=Opaque) + */ +void Widget::SetAlpha(Uint8 Alpha,SDL_Rect *Dest){ + EDL_SetAlpha(simage,Dest,Alpha); +} + +/*! \brief Sets wether widget should respond to mouse input + * \param Show Set to false to hide the widget + */ +void Widget::SetHittable(bool Hittable){ + fhittable=Hittable; +} + +/*! \brief Tells wether widget responds to mouse input + * \returns TRUE if widget is responsive + */ +bool Widget::GetHittable(){ + return fhittable; +} + +/*! \brief Sets widget visibility + * \param Show Set to false to hide the widget + */ +void Widget::SetVisible(bool Show){ + if(fvisible!=Show){ + fvisible=Show; + Refresh(); + } +} + +/*! \brief Tells current visibility + * \returns TRUE if widget is visible + */ +bool Widget::GetVisible(){ + return fvisible; +} + +SDL_Surface *Widget::GetSurface(){ + return simage; +} + +void Widget::Fill(Uint32 Color,SDL_Rect *DRect){ + Uint8 r=(Color>>24)&0xFF; + Uint8 g=(Color>>16)&0xFF; + Uint8 b=(Color>>8)&0xFF; + Uint8 a=Color&0xFF; + Fill(r,g,b,a,DRect); +} + +void Widget::Fill(Uint8 R,Uint8 G,Uint8 B,Uint8 A,SDL_Rect *DRect){ + // Assert source + if(DRect && (!DRect->w || !DRect->h)){ + LogError("Cant fill empty rect"); + } + else if(!DRect && (!pos.w || !pos.h)){ + LogError("Widget has no boundries"); + } + else{ + // Assert target image + if(!simage){ + simage=EDL_CreateSurface(pos.w,pos.h); + } + + // Fill rect + SDL_Rect fill=pos; + fill.x=0; + fill.y=0; + fill.w=pos.w; + fill.h=pos.h; + if(DRect){ + fill.x=DRect->x; + fill.y=DRect->y; + fill.w=DRect->w; + fill.h=DRect->h; + } + boxRGBA(simage,fill.x,fill.y,fill.x+fill.w,fill.y+fill.h,R,G,B,A); + Refresh(); + } +} + +/*! \brief Converts widget surface to a copy of the source + * \param Src Surface to copy from + * \param SrcRect Rectangle to copy from the surface (NULL to match position) + * \param DRect Rectangle to copy to the surface (NULL for entire surface) + */ +void Widget::Set(SDL_Surface *Src,SDL_Rect *SRect,SDL_Rect *DRect){ + if(Src){ + // Find destination rect + int w=pos.w; + int h=pos.h; + if(DRect){ + w=DRect->w; + h=DRect->h; + } + else if(SRect){ + w=SRect->w; + h=SRect->h; + } + else{ + w=Src->w; + h=Src->h; + } + + // Check for resize and reset graphics + if(w!=pos.w || h!=pos.h){ + Resize(w,h); + } + Free(); + Blit(Src,SRect,DRect); + } +} + +/*! \brief Alphablends the given SDL_Rect to the widget surface + * \param Src Surface to copy from + * \param SrcRect Rectangle to copy from the surface (NULL to match position) + * \param DRect Rectangle to copy to the surface (NULL for entire surface) + */ +void Widget::Blend(SDL_Surface *Src,SDL_Rect *SRect,SDL_Rect *DRect){ + if(Src){ + // Assert target image + if(!simage){ + simage=EDL_CreateSurface(pos.w,pos.h); + } + + // Copy surface + if(simage){ + EDL_BlendSurface(Src,SRect,simage,DRect); + Refresh(); + } + } +} + +/*! \brief Blits the given SDL_rect to the widget surface + * \param Src Surface to copy from + * \param SrcRect Rectangle to copy from the surface (NULL to match position) + * \param DRect Rectangle to copy to the surface (NULL for entire surface) + */ +void Widget::Blit(SDL_Surface *Src,SDL_Rect *SRect,SDL_Rect *DRect){ + if(Src){ + // Assert target image + if(!simage){ + simage=EDL_CreateSurface(pos.w,pos.h); + } + + // Copy surface + if(simage){ + EDL_BlitSurface(Src,SRect,simage,DRect); + Refresh(); + } + } +} + +void Widget::Dumpfile(uString Filename){ + if(simage){ + if(!Filename.length()){ + char fb[32]; + int cnt=0; + FILE *fd=0; + do{ + sprintf(fb,"ViLE%04d.BMP",cnt++); + fd=fopen(fb,"r"); + if(fd){ + fclose(fd); + } + }while(fd); + Filename=fb; + } + + // Dump display to file + LogMessage("Dumping graphics:%s",Filename.c_str()); + SDL_SaveBMP(simage,Filename.c_str()); + } +} + +/*! \brief Gets called (very) roughly every 100ms + */ +void Widget::Tick(){ +} + +/*! \brief Blends the current graphics to the destination surface + * \param Dst Destination surface + */ +void Widget::Copy(SDL_Surface *Dst){ + if(Dst){ + if(simage){ + // Blit main surface + SDL_Rect spos={0,0,pos.w,pos.h}; + EDL_BlendSurface(simage,&spos,Dst,&pos); + } + } +} + +/*! \brief Tests wether coordinates are within the bounds of the widget + * \param X Coordinate relative to the native gamesurface + * \param Y Coordinate relative to the native gamesurface + * \returns TRUE if widget would accept this input + */ +bool Widget::TestMouse(int X,int Y){ + int x1=pos.x; + int y1=pos.y; + int x2=x1+pos.w; + int y2=y1+pos.h; + return fvisible && fhittable && (X>=x1 && X<=x2 && Y>=y1 && Y<=y2); +} + +/*! \brief Tests wether the widget is solid (Non-translucent) + * \return True if the widget covers what is beneath + * + * This method was added to version 0.4.10 in order to facilitate smarter + * composite drawing- and caching techinques. It does not propogate so it + * is simple to manage, but its usage is currently experimental. + */ +bool Widget::TestSolid(){ + bool retval=simage && simage->w>=pos.w && simage->h>=pos.h; + if(retval){ + Uint8 r,g,b,a; + EDL_GetPixel(simage,1,1,&r,&g,&b,&a); + if(retval&=(a==0xFF)){ + EDL_GetPixel(simage,pos.w-1,1,&r,&g,&b,&a); + } + if(retval&=(a==0xFF)){ + EDL_GetPixel(simage,1,pos.h-1,&r,&g,&b,&a); + } + if(retval&=(a==0xFF)){ + EDL_GetPixel(simage,pos.w-1,pos.h-1,&r,&g,&b,&a); + } + if(retval&=(a==0xFF)){ + EDL_GetPixel(simage,pos.w/2,pos.h/2,&r,&g,&b,&a); + retval&=(a==0xFF); + } + } + return retval; +} + +/*! \brief Tests wether the widget accepts keyboard input + * \return True if the widget can take keyboard focus + * + * This method was added to version 0.4.10 to improve control and + * distribution of keyboard input. Its introduction means that any widgets + * that wants keyboard input needs to override it. + */ +bool Widget::TestKey(SDLKey Key){ + return false; +} + +bool Widget::FocusEnter(){ + return false; +} + +bool Widget::FocusLeave(){ + return false; +} + +/*! \brief MouseMove event for widgets + * \param X X coordinate + * \param Y Y coordinate + * \return True if widget gobbles input, false if it was ignored + */ +bool Widget::MouseMove(int X,int Y){ + return false; +} + +bool Widget::MouseLeftDown(int X,int Y){ + return false; +} + +bool Widget::MouseRightDown(int X,int Y){ + return false; +} + +bool Widget::MouseLeftUp(int X,int Y){ + return false; +} + +bool Widget::MouseRightUp(int X,int Y){ + return false; +} + +bool Widget::KeyUp(SDLKey Key){ + return false; +} + +bool Widget::KeyDown(SDLKey Key){ + return false; +} + diff --git a/engines/vileVN/widgets/widget.h b/engines/vileVN/widgets/widget.h new file mode 100644 index 0000000000..5c059f29d0 --- /dev/null +++ b/engines/vileVN/widgets/widget.h @@ -0,0 +1,128 @@ +/*! \class Widget + * \brief A generic graphical widget (The key element in ViLE) + * + * The Widget is the core element in ViLE. Any user interaction is picked up + * through widgets, and any graphics are presented to the user though widgets. + * Widgets are managed by the EngineBase class (Altough a Dialog element can + * work as a mediator for a group of widgets) by placing them in different + * layers on screen to build up a graphical interface. + */ +#ifndef _WIDGET_H_ +#define _WIDGET_H_ + +#include "../common/log.h" +#include "../common/dstack.h" +#include "../common/dbuffer.h" +#include "../common/darray.h" +#include "../common/dvector.h" +#include "../common/stringlist.h" +#include "../common/inifile.h" +#include "../common/savegame.h" +#include "../common/cfg.h" +#include "../common/edl_fs.h" +#include "../common/edl_gfx.h" +#include "../res/media.h" + +// Define standard input keys +#define KEY_DIRECTION_H(K) (K==SDLK_LEFT||K==SDLK_RIGHT) +#define KEY_DIRECTION_V(K) (K==SDLK_UP||K==SDLK_DOWN) +#define KEY_DIRECTION(K) (KEY_DIRECTION_H(K)||KEY_DIRECTION_V(K)) +#define KEY_REFOCUS(K) (K==SDLK_TAB) +#define KEY_RETURN(K) (K==SDLK_RETURN||K==SDLK_KP_ENTER) +#define KEY_ACTION_OK(K) (KEY_RETURN(K)||K==SDLK_SPACE) +#define KEY_ACTION_CANCEL(K) (K==SDLK_ESCAPE) +#define KEY_ACTION(K) (KEY_ACTION_OK(K)||KEY_ACTION_CANCEL(K)) + + +// Forward declare group class +class Group; + +class Widget { + private: + // Helpers + void setdefaults(); + protected: + // data .. lotsa data + static bool global_refresh; //!< Wether we need to refresh + static SDL_Rect global_update; //!< Tracks updated graphics + bool local_refresh; //!< Wether we need to refresh + SDL_Rect local_update; //!< Tracks updated graphics + SDL_Rect pos; //!< Screen position + SDL_Surface *simage; //!< Primary surface image + bool fhittable; //!< Accepts mouse input + bool fvisible; //!< Onscreen visibility + Uint8 valpha; //!< Alpha value + Uint32 tag; //!< Freeform data tag + public: + // Constructors to force key settings + Widget(int X,int Y,int Width,int Height); + Widget(SDL_Rect Position); + Widget(); + virtual ~Widget(); + + // Surface options + void SetAlpha(Uint8 Alpha,SDL_Rect *Destination=0); + + // Visibility options + virtual void SetVisible(bool Show); + virtual void SetHittable(bool Hittable); + bool GetVisible(); + bool GetHittable(); + + // Manipulate graphics directly + virtual void Move(SDL_Rect Position); + virtual void Move(int X,int Y); + virtual void Resize(int Width,int Height); + void Fill(Uint32 Color,SDL_Rect *DRect=0); + void Fill(Uint8 R,Uint8 G,Uint8 B,Uint8 A,SDL_Rect *DRect=0); + void Set(SDL_Surface *Src,SDL_Rect *SRect=0,SDL_Rect *DRect=0); + void Blit(SDL_Surface *Src,SDL_Rect *SRect=0,SDL_Rect *DRect=0); + void Blend(SDL_Surface *Src,SDL_Rect *SRect=0,SDL_Rect *DRect=0); + void Dumpfile(uString Filename=""); + SDL_Surface *GetSurface(); + void Free(); + + // Get positiondata + int GetX(); + int GetY(); + int GetWidth(); + int GetHeight(); + SDL_Rect GetPosition(); + + // Wether display needs refresh + static bool GetGlobalRefresh(SDL_Rect *Cliprect=0); + static bool PeekGlobalRefresh(SDL_Rect *Cliprect=0); + virtual bool GetLocalRefresh(SDL_Rect *Cliprect=0); + virtual bool PeekLocalRefresh(SDL_Rect *Cliprect=0); + virtual void Refresh(SDL_Rect *Update=0); + static void Redraw(); + + // Data assignment + void SetTag(Uint32 Tag); + Uint32 GetTag(); + + // Internal management and control interface + virtual void Copy(SDL_Surface *Dst); + virtual bool TestKey(SDLKey Key); + virtual bool TestMouse(int X,int Y); + virtual bool TestSolid(); + + // Engine events + virtual void Tick(); + virtual bool FocusEnter(); + virtual bool FocusLeave(); + virtual bool MouseMove(int X,int Y); + virtual bool MouseLeftUp(int X,int Y); + virtual bool MouseRightUp(int X,int Y); + virtual bool MouseLeftDown(int X,int Y); + virtual bool MouseRightDown(int X,int Y); + virtual bool KeyUp(SDLKey Key); + virtual bool KeyDown(SDLKey Key); + + // Stacking pointers for driver classes + Widget *PrevPtr; + Widget *NextPtr; +}; + +#endif + diff --git a/engines/vileVN/widgets/zoom.cpp b/engines/vileVN/widgets/zoom.cpp new file mode 100644 index 0000000000..9cc5fd271d --- /dev/null +++ b/engines/vileVN/widgets/zoom.cpp @@ -0,0 +1,192 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "zoom.h" + +Zoom::Zoom(SDL_Rect Dst) : Animation(Dst) { + // Set default values + EDL_SETRECT(start,0,0,0,0); + EDL_SETRECT(end,0,0,0,0); + t_start=0; + t_duration=0; + source=0; +} + +Zoom::Zoom(SDL_Surface *Surface,SDL_Rect Source, + SDL_Rect Start,SDL_Rect End,Uint32 Duration) : Animation(Start) { + // Set default values + EDL_SETRECT(start,0,0,0,0); + EDL_SETRECT(end,0,0,0,0); + t_start=0; + t_duration=0; + source=0; + + // Prepare surface + SetZoom(Surface,Source,Start,End,Duration); +} + +Zoom::~Zoom(){ + if(source){ + SDL_FreeSurface(source); + } +} + +void Zoom::SetZoom(SDL_Surface *Surface,SDL_Rect Source, + SDL_Rect Start,SDL_Rect End,Uint32 Duration){ + // Configure object + t_duration=Duration; + t_start=0; + start=Start; + end=End; + + // Copy graphics + if(source){ + SDL_FreeSurface(source); + } + source=EDL_CopySurface(Surface,&Source); +} + +/*! \brief Completes the running fade effect + * + * The finished graphics are copied to the primary widget surface + * and the animation surface is deleted. Subsequent calls to Copy() + * will use the widget graphics as source. + */ +bool Zoom::Skip(){ + bool retval=source; + if(source){ + // Complete zoom + SDL_Surface *zoom=0; + SDL_Rect rect; + if(ZoomSurface(100,&zoom,&rect)){ + if(simage){ + SDL_FreeSurface(simage); + } + simage=zoom; + Move(rect); + Refresh(); + } + SDL_FreeSurface(source); + source=0; + } + return retval; +} + +/*! \brief Tells wether animation should continue + * \return True if animation is running + */ +bool Zoom::Continue(){ + return source!=0; +} + +/*! \brief Copies graphics + * \param Dst Target surface + */ +void Zoom::Copy(SDL_Surface *Dst){ + if(source){ + if(!t_start){ + // Assert time + t_start=SDL_GetTicks(); + Move(start); + } + Uint32 now=SDL_GetTicks(); + if(now>=t_start+t_duration){ + // Zoom is complete ... + SDL_Surface *zoom=0; + SDL_Rect rect; + if(ZoomSurface(100,&zoom,&rect)){ + if(simage){ + SDL_FreeSurface(simage); + } + simage=zoom; + Move(rect); + Refresh(); + } + if(source){ + SDL_FreeSurface(source); + source=0; + } + } + else{ + // Calculate a new step based upon time + double p=(now-t_start)/(double)t_duration; + SDL_Surface *zoom=0; + SDL_Rect rect; + if(ZoomSurface(p*100,&zoom,&rect)){ + if(simage){ + SDL_FreeSurface(simage); + } + simage=zoom; + Move(rect); + Refresh(); + } + } + } + + Widget::Copy(Dst); +} + +bool Zoom::ZoomSurface(double Progress,SDL_Surface **Surface,SDL_Rect *Rect){ + bool retval=false; + if(source){ + Progress=Progress/100; + SDL_Rect c; + if(end.x>start.x){ + // Move right + c.x=start.x+((end.x-start.x)*Progress); + } + else{ + // Move left + c.x=end.x+((start.x-end.x)*(1-Progress)); + } + if(end.y>start.y){ + // Move down + c.y=start.y+((end.y-start.y)*Progress); + } + else{ + // Move up + c.y=end.y+((start.y-end.y)*(1-Progress)); + } + + if(end.w>start.w){ + // Expand + c.w=start.w+((end.w-start.w)*Progress); + } + else{ + // Shrink + c.w=end.w+((start.w-end.w)*(1-Progress)); + } + if(end.h>start.h){ + // Expand + c.h=start.h+((end.h-start.h)*Progress); + } + else{ + // Shrink + c.h=end.h+((start.h-end.h)*(1-Progress)); + } + + // Scale widget image and redraw using base + if(c.w>1 && c.h>1 && !(c.w&0x8000) && !(c.h&0x8000)){ + if((*Surface=zoomSurface(source, + c.w/(double)source->w, + c.h/(double)source->h,1))){ + *Rect=c; + retval=true; + } + } + } + return retval; +} + diff --git a/engines/vileVN/widgets/zoom.h b/engines/vileVN/widgets/zoom.h new file mode 100644 index 0000000000..a8869161ac --- /dev/null +++ b/engines/vileVN/widgets/zoom.h @@ -0,0 +1,32 @@ +/*! \class Zoom + * \brief Zoom animation widget + */ +#ifndef _ZOOM_H_ +#define _ZOOM_H_ + +#include "animation.h" +#include + +class Zoom : public Animation { + private: + // Common + SDL_Surface *source; //!< Surface to zoom or whatever into + SDL_Rect start; + SDL_Rect end; + Uint32 t_start; //!< Time the effect started + Uint32 t_duration; //!< How long the effect should run + public: + Zoom(SDL_Rect Dst); + Zoom(SDL_Surface *Surface,SDL_Rect Source,SDL_Rect Start, + SDL_Rect End,Uint32 Duration); + ~Zoom(); + void SetZoom(SDL_Surface *Surface,SDL_Rect Source, + SDL_Rect Start,SDL_Rect End,Uint32 Duration); + bool ZoomSurface(double Progress,SDL_Surface **Surface,SDL_Rect *Rect); + void Copy(SDL_Surface *Dst); + bool Skip(); + bool Continue(); +}; + +#endif + diff --git a/engines/vileVN/will/critical/critical.cpp b/engines/vileVN/will/critical/critical.cpp new file mode 100644 index 0000000000..afce80b4d0 --- /dev/null +++ b/engines/vileVN/will/critical/critical.cpp @@ -0,0 +1,53 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "critical.h" + +CriticalPoint::CriticalPoint(uString Path) : EngineWill(640,480) { + // Add resources + AddBGM(new ArchiveWillARC(Path+"bgm.arc")); + AddVoices(new ArchiveWillARC(Path+"voice.arc")); + AddSE(new ArchiveWillARC(Path+"se.arc")); + AddScripts(new ArchiveWillARC(Path+"rio.arc")); + AddImages(new ArchiveWillARC(Path+"chip.arc")); + AddOther(new ArchiveWillARC(Path+"chip.arc")); + AddVideo(new ArchiveWillARC(Path+"ending.dat")); + AddVideo(new ArchiveFiles(Path+"peach.dat")); + + // Configure textview + //DestroyWidget(textview); + //textview=new YumeTextview(this); + //AddWidget(textview,VL_TEXTVIEW); + + // Configure textview + //selection->Move(100,396); + //selection->Resize(440,70); + selection->Resize(640/3,480/3); + selection->Move(640/3,480/3); + selection->SetAlignment(HA_CENTER,VA_CENTER); + + // Show main menu + EventGameDialog(VD_TITLE); +} + +const uString CriticalPoint::NativeID(){ + return "Critical"; +} + +const uString CriticalPoint::NativeName(){ + return "Critical Point"; +} + + diff --git a/engines/vileVN/will/critical/critical.h b/engines/vileVN/will/critical/critical.h new file mode 100644 index 0000000000..a34de28465 --- /dev/null +++ b/engines/vileVN/will/critical/critical.h @@ -0,0 +1,26 @@ +/*! \class CriticalPoint + * \brief Critical Point implementation + * + * This implementation is just to test backwards compability of EngineWill. + * + * The compability seems pretty horrible at first glance. + */ + +#ifndef _CRITICAL_H_ +#define _CRITICAL_H_ + +#include "../will.h" + +class CriticalPoint : public EngineWill { + private: + public: + CriticalPoint(uString Path); + + // Overrides + virtual const uString NativeID(); + virtual const uString NativeName(); +}; + +#endif + + diff --git a/engines/vileVN/will/will.cpp b/engines/vileVN/will/will.cpp new file mode 100644 index 0000000000..ce5d5544cd --- /dev/null +++ b/engines/vileVN/will/will.cpp @@ -0,0 +1,1395 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "will.h" + + +EngineWill::EngineWill(int Width,int Height) : EngineVN(Width,Height){ + // Set defaults + effect=0; + table_data=0; + table_mouseindex=0; + anim_data=0; + script=0; + ticks_value=0; + ticks_stamp=SDL_GetTicks(); + state=WILLSTATE_NORMAL; + + // Load gui interface + int owidth=Width/3; + display=new Widget(0,0,Width,Height); + overlay[0]=new Widget(owidth*0,0,Width,Height); + overlay[1]=new Widget(owidth*1,0,Width,Height); + overlay[2]=new Widget(owidth*2,0,Width,Height); + textview=new Textview(this); + selection=new Selection(this); + AddWidget(display,VL_BACKGROUND); + AddWidget(overlay[0],VL_BACKGROUND); + AddWidget(overlay[1],VL_BACKGROUND); + AddWidget(overlay[2],VL_BACKGROUND); + AddWidget(textview,VL_TEXTVIEW); + AddWidget(selection,VL_CHOICES); + + // Prelod 3000 signed shorts. (For Yume only?) + //vars.SetSint16(3000,0); +} + +EngineWill::~EngineWill(){ + Stop(); + if(table_data){ + if(table_data->surface){ + SDL_FreeSurface(table_data->surface); + } + delete table_data; + } + if(anim_data){ + for(int i=0;anim_data->frames[i];i++){ + SDL_FreeSurface(anim_data->frames[i]); + } + delete anim_data; + } + if(effect){ + SDL_FreeSurface(effect); + } +} + +/*! \brief Tells wether a script is loaded + * \returns True if a script is properly loaded + */ +bool EngineWill::Running(){ + return script && script->buffer; +} + +/*! \brief Stops the engine and flushes any script data + */ +void EngineWill::Stop(){ + while(script){ + if(script->buffer){ + delete [] script->buffer; + } + SCRIPT *tmp=script->nextptr; + delete script; + script=tmp; + } +} + +/*! \brief Jumps to an absolute position in the current script + * \param Byteposition in the script + */ +bool EngineWill::Jump(unsigned int Position){ + bool retval=false; + if(script){ + if(Positionlength){ + script->index=Position; + state=WILLSTATE_NORMAL; + retval=true; + } + } + return retval; +} + +/*! \brief Extracts positional data from WIPF images + * \param Name Name of image resource + * \param Index Framenumber in image resource + * \paeam Rect Rect to be populated with position data + * + * WIPF images has coordinates stored in the header, and the SDL_Surface + * structure cannot hold the X and Y positions. This method parses out the + * necessary parameters without touching the graphics. + */ +bool EngineWill::GetImagePosition(uString Name,Uint8 Index,SDL_Rect *Rect){ + bool retval; + RWops *Object=LoadOther(Name,"wip"); + if(Object){ + Uint8 hdr[24]; + Object->Seek(0,SEEK_SET); + Object->Read(hdr,8); + unsigned int count=hdr[4]|(hdr[5]<<8); + if(hdr[0]=='W' && hdr[1]=='I' && hdr[2]=='P' && hdr[3]=='F'){ + unsigned int pos=8+(Index*24); + if(count>Index){ + Object->Seek(pos,SEEK_SET); + if(Object->Read(hdr,24)==24){ + int w=hdr[0]|(hdr[1]<<8)|(hdr[2]<<16)|(hdr[3]<<24); + int h=hdr[4]|(hdr[5]<<8)|(hdr[6]<<16)|(hdr[7]<<24); + int x=hdr[8]|(hdr[9]<<8)|(hdr[10]<<16)|(hdr[11]<<24); + int y=hdr[12]|(hdr[13]<<8)|(hdr[14]<<16)|(hdr[15]<<24); + if(Rect){ + Rect->x=x; + Rect->y=y; + Rect->w=w; + Rect->h=h; + retval=true; + } + } + + } + } + delete Object; + } + return retval; +} + +/*! \brief Loads and parses a Will ANM file + * \param Name Name of animation file + * + * Note that the animation infrastructure is often used for other purposes. + * such as menu graphics and properties. + */ +WILLANIMATION *EngineWill::LoadAnimation(uString Name){ + WILLANIMATION *retval=0; + RWops *blob=0; + if((blob=LoadOther(Name,"anm")) && blob->Size()){ + int size=blob->Size(); + unsigned char buffer[size]; + if(blob->Read(buffer,size)==size){ + retval=new WILLANIMATION; + retval->name=(char*)buffer; + retval->frames=EngineVN::LoadAnimation(retval->name); + if(retval->frames){ + for(int i=0;i<100;i++){ + for(int j=0;j<402;j++){ + int a=9+(((i*401)+j)*2); + retval->entries[i][j]=GETWORD(buffer+a); + } + } + for(int i=0;i<100;i++){ + retval->visible[i]=true; + } + } + else{ + LogError("Failed to load animation frames: %s",buffer); + delete retval; + retval=0; + } + } + delete blob; + } + return retval; +} + +/*! \brief Loads a Will table + * \param Name Table resource + */ +WILLTABLE *EngineWill::LoadTable(uString Name){ + WILLTABLE *retval=0; + RWops *blob=0; + if((blob=LoadOther(Name,"tbl")) && blob->Size()){ + int size=blob->Size(); + unsigned char buffer[size]; + if(blob->Read(buffer,size)==size){ + retval=new WILLTABLE; + retval->count=GETDWORD(buffer); + retval->surface=LoadImage((char*)buffer+4); +//LogTest("NAME:%s IMAGE:%s COUNT:%d",Name.c_str(),buffer+4,retval->count); + if(retval->surface){ + for(int i=0;i<0xFF;i++){ + retval->flags[i+1]=GETDWORD(buffer+4+9+(i*4)); +//if(retval->flags[i+1]){ +//LogTest("FLAGS[%X]=0x%08X",i,retval->flags[i+1]); +//} + } + for(int i=0;i<0x12;i++){ + for(int j=0;j<0x10;j++){ + int p=4+9+(0xFe*4)+(i*0x10)+j; + retval->keymap[i][j]=GETBYTE(buffer+p); +//if(retval->keymap[i][j]){ +//LogTest("KEYMAP[%X][%X]=0x%04X (%d/%d)",i,j,retval->keymap[i][j],p,size); +//} + } + } + } + else{ + LogError("Failed to load table graphic: %s",buffer+4); + delete retval; + retval=0; + } + } + delete blob; + } + return retval; +} + +/*! \brief Loads a masked Will image (msk+wip=>alpha) + * \param Resource name + */ +SDL_Surface *EngineWill::LoadMaskedImage(uString Name){ + SDL_Surface *mask=LoadImage(Name,"msk"); + SDL_Surface *image=LoadImage(Name,"wip"); + if(mask && image){ + // Copy mask + int w=EDL_MIN(mask->w,image->w); + int h=EDL_MIN(mask->h,image->h); + if(SDL_MUSTLOCK(mask)){ + if(SDL_LockSurface(mask)<0){ + return image; + } + } + if(SDL_MUSTLOCK(image)){ + if(SDL_LockSurface(image)<0){ + return 0; + } + } + for(int y=0;y(mask->pixels)+ + (y*mask->pitch)+(x*mask->format->BytesPerPixel); + Uint8 *dstp=static_cast(image->pixels)+ + (y*image->pitch)+(x*image->format->BytesPerPixel); + dstp[3]=srcp[0]; + } + } + if(SDL_MUSTLOCK(mask)){ + SDL_UnlockSurface(mask); + } + if(SDL_MUSTLOCK(image)){ + SDL_UnlockSurface(image); + } + } + if(mask){ + SDL_FreeSurface(mask); + } + return image; +} + +/*! \brief Loads a masked Will image (msk+wip=>alpha) + * \param Resource name + */ +SDL_Surface **EngineWill::LoadMaskedAnimation(uString Name){ + SDL_Surface **mask=EngineVN::LoadAnimation(Name,"msk"); + SDL_Surface **image=EngineVN::LoadAnimation(Name,"wip"); + for(int i=0;mask[i] && image[i];i++){ + // Copy mask + int w=EDL_MIN(mask[i]->w,image[i]->w); + int h=EDL_MIN(mask[i]->h,image[i]->h); + if(SDL_MUSTLOCK(mask[i])){ + if(SDL_LockSurface(mask[i])<0){ + return 0; + } + } + if(SDL_MUSTLOCK(image[i])){ + if(SDL_LockSurface(image[i])<0){ + return 0; + } + } + for(int y=0;y(mask[i]->pixels)+ + (y*mask[i]->pitch)+(x*mask[i]->format->BytesPerPixel); + Uint8 *dstp=static_cast(image[i]->pixels)+ + (y*image[i]->pitch)+(x*image[i]->format->BytesPerPixel); + dstp[3]=srcp[0]; + } + } + if(SDL_MUSTLOCK(mask[i])){ + SDL_UnlockSurface(mask[i]); + } + if(SDL_MUSTLOCK(image[i])){ + SDL_UnlockSurface(image[i]); + } + } + if(mask){ + for(int i=0;mask[i];i++){ + SDL_FreeSurface(mask[i]); + } + delete [] mask; + } + return image; +} + + +/*! \brief Loads a Will script and pushes it on top of the stack + * \param Script Name of the script file + * \return True if script loaded + */ +bool EngineWill::LoadWillScript(uString Script){ + bool retval=false; + RWops *blob=0; + if((blob=LoadScript(Script,"wsc"))){ + // Extract and verify data + LogVerbose("Loading Will script: %s",Script.c_str()); + int tlength=blob->Seek(0,SEEK_END); + if(tlength>(int)0){ + // Replace blob + blob->Seek(0,SEEK_SET); + unsigned char *tbuffer=new unsigned char[tlength]; + if(blob->Read(tbuffer,tlength)>(int)0){ + // Decrypt script data + int p=2%8; + for(int i=0;i>p)|(tbuffer[i]<<(8-p)); + } + + // Push script data to stack + SCRIPT *tmp=new SCRIPT; + tmp->name=Script; + tmp->buffer=tbuffer; + tmp->length=tlength; + tmp->index=0; + tmp->save=0; + tmp->nextptr=script; + script=tmp; + retval=true; + + // Force new start + textview->ClearText(); + state=WILLSTATE_NORMAL; + } + } + delete blob; + } + return retval; +} + +bool EngineWill::EventBackgroundMouseMove(int X,int Y){ + if(state==WILLSTATE_GUI){ + if(table_data && table_data->surface){ + SDL_Surface *s=table_data->surface; + if(X>0 &&Xw && Y>0 && Yh){ + Uint8 *pixels=static_cast + (s->pixels)+(Y*s->pitch)+ + (X*s->format->BytesPerPixel); + if(pixels[0]!=table_mouseindex){ + // Get image position and blit it + table_mouseindex=pixels[0]; + SDL_Rect r; + if(GetImagePosition(anim_data->name,table_mouseindex,&r)){ + SDL_Surface *frame=anim_data->frames[table_mouseindex]; + if(frame){ + display->Blit(frame,0,&r); + } + } + } + } + } + } + else{ + return EngineVN::EventBackgroundMouseMove(X,Y); + } + return false; +} + +bool EngineWill::EventBackgroundMouseLeftDown(int X,int Y){ + bool retval=false; + if(state==WILLSTATE_GUI){ + if(table_data && table_data->surface){ + SDL_Surface *s=table_data->surface; + if(X>0 &&Xw && Y>0 && Yh){ + Uint8 *pixels=static_cast + (s->pixels)+(Y*s->pitch)+ + (X*s->format->BytesPerPixel); + if(pixels[0]){ + // Set click vars + vars.SetUint16(table_varclick,1); + vars.SetUint16(table_varkind,pixels[0]); + state=WILLSTATE_NORMAL; + retval=true; + } + } + } + } + else{ + retval=EngineVN::EventBackgroundMouseLeftDown(X,Y); + } + return retval; +} + +bool EngineWill::EventBackgroundMouseRightDown(int X,int Y){ + bool retval=false; + if(state==WILLSTATE_GUI){ + if(table_data && table_data->surface){ + // Set click vars + vars.SetUint16(table_varclick,-1); + vars.SetUint16(table_varkind,0); + state=WILLSTATE_NORMAL; + } + } + else{ + retval=EngineVN::EventBackgroundMouseRightDown(X,Y); + } + return retval; +} + +bool EngineWill::EventLoad(int Index){ + bool retval=false; + Savegame *load=new Savegame(NativeID(),Index); + if(load->Read()){ + // Clear existing data + selection->SetVisible(false); + textview->ClearText(); + Stop(); + + // Recreate script stack + Uint32 count=0; + load->LoadUint32("size",&count); + for(int i=count;i>0;i--){ + uString name; + Uint32 index; + load->LoadString(EDL_Format("name-%d",i-1),&name); + load->LoadUint32(EDL_Format("index-%d",i-1),&index); + LoadWillScript(name); + script->index=index; + script->save=index; + } + load->LoadVector("variables",&vars); + state=WILLSTATE_NORMAL; + + // Load graphics + SDL_Surface *tmps; + if(load->LoadSurface("screen-display",&tmps)){ + display->Blit(tmps); + SDL_FreeSurface(tmps); + } + + // Close dialog + retval=true; + } + delete load; + return retval; +} + +bool EngineWill::EventSave(int Index){ + // Gather date string + uString date=EDL_DateString(EDL_UnixTime()); + uString time=EDL_TimeString(EDL_UnixTime()); + uString datetime=date+uString(" ")+time; + + // Store script data + Savegame *save=new Savegame(NativeID(),Index); + int count=0; + SCRIPT *tmpptr=script; + while(tmpptr){ + int index=tmpptr->nextptr?tmpptr->index:tmpptr->save; + save->SaveString(EDL_Format("name-%d",count),tmpptr->name); + save->SaveUint32(EDL_Format("index-%d",count),index); + tmpptr=tmpptr->nextptr; + count++; + } + save->SaveUint32("size",count); + save->SaveVector("variables",&vars); + save->SaveString("savedate",datetime); + save->SaveString("savemsg",GetSavename()); + + // Store graphics + SDL_Surface *screen=EDL_CreateSurface(NativeWidth(),NativeHeight()); + Paint(screen,VL_BACKGROUND); + save->SaveSurface("screen-thumb",screen,96,72); + save->SaveSurface("screen-display",screen); + SDL_FreeSurface(screen); + + // Close dialogs + save->Write(); + delete save; + return true; +} + +void EngineWill::EventSelect(int Selection){ + selection->SetVisible(false); + uString name=jumptable.GetString(Selection); + LoadWillScript(name); +} + +void EngineWill::EventGameDialog(VN_DIALOGS Dialog){ + if(Dialog==VD_TITLE){ + DestroyLayer(VL_OVERLAY); + DestroyLayer(VL_EXTRAS); + textview->SetVisible(false); + LoadWillScript("start"); + } + else{ + EngineVN::EventGameDialog(Dialog); + } +} + +bool EngineWill::EventGameTick(){ + if(state==WILLSTATE_WAITCLICK){ + bool skip=keyok || keyctrl() || GetSkipmode(); + if(skip && textview->GetRemainingText()){ + textview->CompleteText(); + keyok=false; + } + else if(skip){ + StopSound(VA_VOICES); + state=WILLSTATE_NORMAL; + textview->ClearText(); + keyok=false; + } + } + return !(state==WILLSTATE_NORMAL && !textview->GetRemainingText()); +} + +bool EngineWill::EventGameProcess(){ + bool retval=true; + if(script && script->buffer && script->indexlength){ + Uint8 opcode=GETBYTE(script->buffer+script->index); + script->index++; +//LogTest("PROCESS: 0x%02X",opcode); + // Flow opcodes + if(opcode==0x01) retval=OP01(); + else if(opcode==0x02) retval=OP02(); + else if(opcode==0x03) retval=OP03(); + else if(opcode==0x04) retval=OP04(); + else if(opcode==0x06) retval=OP06(); + else if(opcode==0x07) retval=OP07(); + else if(opcode==0x09) retval=OP09(); + else if(opcode==0x0A) retval=OP0A(); + else if(opcode==0xFF) retval=OPFF(); + + // Audio opcodes + else if(opcode==0x21) retval=OP21(); + else if(opcode==0x22) retval=OP22(); + else if(opcode==0x23) retval=OP23(); + else if(opcode==0x25) retval=OP25(); + else if(opcode==0x26) retval=OP26(); + else if(opcode==0x52) retval=OP52(); + + // Display codes + else if(opcode==0x46) retval=OP46(); + else if(opcode==0x47) retval=OP47(); + else if(opcode==0x48) retval=OP48(); + else if(opcode==0x49) retval=OP49(); + else if(opcode==0x64) retval=OP64(); + else if(opcode==0x68) retval=OP68(); + else if(opcode==0x73) retval=OP73(); + else if(opcode==0x74) retval=OP74(); + else if(opcode==0xB8) retval=OPB8(); + + // Other + else if(opcode==0x05) retval=OP05(); + else if(opcode==0x08) retval=OP08(); + else if(opcode==0x0B) retval=OP0B(); + else if(opcode==0x0C) retval=OP0C(); + else if(opcode==0x41) retval=OP41(); + else if(opcode==0x42) retval=OP42(); + else if(opcode==0x43) retval=OP43(); + else if(opcode==0x45) retval=OP45(); + else if(opcode==0x4A) retval=OP4A(); + else if(opcode==0x4B) retval=OP4B(); + else if(opcode==0x4C) retval=OP4C(); + else if(opcode==0x4D) retval=OP4D(); + else if(opcode==0x4F) retval=OP4F(); + else if(opcode==0x50) retval=OP50(); + else if(opcode==0x51) retval=OP51(); + else if(opcode==0x54) retval=OP54(); + else if(opcode==0xB6) retval=OPB6(); + else if(opcode==0x61) retval=OP61(); + else if(opcode==0x82) retval=OP82(); + else if(opcode==0x83) retval=OP83(); + else if(opcode==0x84) retval=OP84(); + else if(opcode==0x8B) retval=OP8B(); + else if(opcode==0xE2) retval=OPE2(); + + // Trap unknown codes + else if(opcode==0x28) retval=OPXX(3); + else if(opcode==0x29) retval=OPXX(4); + else if(opcode==0x30) retval=OPXX(4); + else if(opcode==0x4E) retval=OPXX(4); + else if(opcode==0x55) retval=OPXX(1); + else if(opcode==0x62) retval=OPXX(1); + else if(opcode==0x76) retval=OPXX(9); + else if(opcode==0x85) retval=OPXX(2); + else if(opcode==0x86) retval=OPXX(2); + else if(opcode==0x88) retval=OPXX(3); + else if(opcode==0x89) retval=OPXX(1); + else if(opcode==0x8A) retval=OPXX(1); + else if(opcode==0x8C) retval=OPXX(3); + else if(opcode==0x8E) retval=OPXX(1); + else if(opcode==0xBC) retval=OPXX(4); + else if(opcode==0xBD) retval=OPXX(2); + else if(opcode==0xBE) retval=OPXX(1); + else if(opcode==0xE5) retval=OPXX(1); + else{ + LogError("Invalid opcode: 0x%02X",opcode); + } + } + return retval; +} + +/*! Conditional if + */ +bool EngineWill::OP01(){ + // Parse input data + Uint8 operation=GETBYTE(script->buffer+script->index+0); + Uint16 leftreg=GETWORD(script->buffer+script->index+1); + Uint16 rightreg=GETWORD(script->buffer+script->index+3); + Uint32 pos=GETDWORD(script->buffer+script->index+5); + script->index+=10; + + // Parse values and operator + Uint8 op=operation&0x0F; + Sint16 leftval=vars.GetSint16(leftreg); + Sint16 rightval=rightreg; + if(operation>>4){ + rightval=vars.GetSint16(rightreg); + } + + // Jump if test fails + bool test=false; + switch(op){ + case 1: test=!(leftval>=rightval); break; + case 2: test=!(leftval<=rightval); break; + case 3: test=!(leftval==rightval); break; + case 4: test=!(leftval!=rightval); break; + case 5: test=!(leftval>rightval); break; + case 6: test=!(leftvalindex+pos); + } + return false; +} + +/*! \brief Show selection + */ +bool EngineWill::OP02(){ + script->save=script->index-1; + Uint16 n=GETWORD(script->buffer+script->index); + script->index+=2; + + // Parse selection structure + SDL_Surface *normal=LoadMaskedImage("selwnd0"); + SDL_Surface *hover=LoadMaskedImage("selwnd1"); + int space=10; + int w=normal->w; + int h=normal->h; + int x=(NativeWidth()-w)/2; + int y=(NativeHeight()-(h*n+space*n))/2; + jumptable.Clear(); + for(int i=0;ibuffer+script->index); + script->index+=2; + aString text; + while(script->buffer[script->index]){ + text+=script->buffer[script->index++]; + } + script->index++; + //Uint32 unknown=GETDWORD(script->buffer+script->index); + script->index+=4; + aString target; + while(script->buffer[script->index]){ + target+=script->buffer[script->index++]; + } + script->index++; + + // Add item to jumptable + jumptable.AddString(target); + + // Add item to selection + SDL_Rect r={x,y,w,h}; + SDL_Surface *s=EDL_CreateSurface(w,h); + SDL_Surface *u=EDL_CreateSurface(w,h); + EDL_BlitSurface(hover,0,s,0); + EDL_BlitSurface(normal,0,u,0); + EDL_BlendText(text,0xFFFFFFFF,s,0); + EDL_BlendText(text,0xFFFFFFFF,u,0); + selection->SetSurface(s,u,r,i); + SDL_FreeSurface(s); + SDL_FreeSurface(u); + y+=(h+space); + } + if(normal){ + SDL_FreeSurface(normal); + } + if(hover){ + SDL_FreeSurface(hover); + } + selection->SetVisible(true); + state=WILLSTATE_CHOICE; + return true; +} + +/*! Calculations + */ +bool EngineWill::OP03(){ + // Parse input data + Uint8 op=GETBYTE(script->buffer+script->index+0); + Uint16 leftreg=GETWORD(script->buffer+script->index+1); + Uint8 flag=GETBYTE(script->buffer+script->index+3); + Uint16 rightreg=GETWORD(script->buffer+script->index+4); + script->index+=7; + + // Parse values and operator + Sint16 leftval=vars.GetSint16(leftreg); + Sint16 rightval=rightreg; + if(flag){ + rightval=vars.GetSint16(rightreg); + } + if(op){ + // Calculate result + int result=0; + switch(op){ + case 1: result=rightval; break; + case 2: result=leftval+rightval; break; + case 3: result=leftval-rightval; break; + case 4: result=vars.GetSint16(rightval); break; + case 5: result=leftval%rightval; break; + case 6: result=rand()%rightval; break; + default: LogError("Unknown CALC operator: %d",op); break; + } + vars.SetSint16(leftreg,result); + } + else{ + // Flush temporary flags + for(int i=0;i<1000;i++){ + vars.SetSint16(i,0); + } + } + return false; +} + +/*! Quit application + */ +bool EngineWill::OP04(){ + Stop(); + EventGameShutdown(); + return true; +} + +/*! Wait until timer reaces NULL + */ +bool EngineWill::OP05(){ + Uint8 skippable=GETBYTE(script->buffer+script->index+0); + script->index++; +LogTest("OP05:WAIT:%d",skippable); + return true; +} + +/*! Unconditional jump (Absolute) + */ +bool EngineWill::OP06(){ + Uint32 pos=GETDWORD(script->buffer+script->index+0); + script->index+=5; + Jump(pos); + return false; +} + +/*! Sets the timer (In tick at 25 fps) + */ +bool EngineWill::OP0B(){ + Uint16 ticks=GETWORD(script->buffer+script->index+0); + script->index+=2; + //ticks_value=ticks*((1/25)*1000); + ticks_value=ticks; + ticks_stamp=SDL_GetTicks(); + return false; +} + +/*! Check the timer + */ +bool EngineWill::OP0C(){ + Uint16 flag=GETWORD(script->buffer+script->index+0); + script->index+=3; + + // Check timer ticks + if(ticks_value){ + Uint32 now=SDL_GetTicks(); + Uint32 ticked=now-ticks_stamp; + ticks_stamp=now; + if(ticks_value>ticked){ + ticks_value-=ticked; + } + else{ + ticks_value=0; + } + } + vars.SetSint16(flag,ticks_value==0); +LogTest("OP0C:TIMER:%d=%d",flag,ticks_value); + return false; +} + +/*! Load new script + */ +bool EngineWill::OP07(){ + aString text; + while(script->buffer[script->index]){ + text+=script->buffer[script->index++]; + } + script->index++; + Stop(); + LogVerbose("Loading script: %s",text.c_str()); + LoadWillScript(text); + return false; +} + +/*! Set text size (big/small) + */ +bool EngineWill::OP08(){ + Uint16 size=GETWORD(script->buffer+script->index+0); + script->index+=2; +LogTest("OP08:Size=%d",size); + return false; +} + +/*! Call script + */ +bool EngineWill::OP09(){ + aString text; + while(script->buffer[script->index]){ + text+=script->buffer[script->index++]; + } + script->index++; + LogVerbose("Calling script: %s",text.c_str()); + LoadWillScript(text); + return false; +} + +/*! Return from a called script + */ +bool EngineWill::OP0A(){ + LogVerbose("Returning"); + //Uint8 param=GETBYTE(script->buffer+script->index+0); + if(script->buffer){ + delete [] script->buffer; + } + SCRIPT *tmp=script->nextptr; + delete script; + script=tmp; + return false; +} + +/*! Play musac + */ +bool EngineWill::OP21(){ + //Uint8 repeats=GETBYTE(script->buffer+script->index+0); + //Uint16 fadein=GETWORD(script->buffer+script->index+1); + script->index+=3; + aString text; + while(script->buffer[script->index]){ + text+=script->buffer[script->index++]; + } + script->index++; + PlayMusic(text); + return false; +} + +/*! Stop musac + */ +bool EngineWill::OP22(){ + //Uint16 fadeout=GETWORD(script->buffer+script->index+1); + script->index+=4; + StopMusic(); + return false; +} + +/*! Play voice + */ +bool EngineWill::OP23(){ + Uint8 channel=GETBYTE(script->buffer+script->index+0); + //Uint8 male=GETBYTE(script->buffer+script->index+4); + script->index+=7; + aString text; + while(script->buffer[script->index]){ + text+=script->buffer[script->index++]; + } + script->index++; + PlayVoice(text,channel); + return false; +} + +/*! Play sound + */ +bool EngineWill::OP25(){ + Uint8 channel=GETBYTE(script->buffer+script->index+0); + Uint8 repeat=GETBYTE(script->buffer+script->index+1); + //Uint8 start=GETBYTE(script->buffer+script->index+3); + //Uint16 fadein=GETWORD(script->buffer+script->index+4); + //Uint16 volume=GETWORD(script->buffer+script->index+6); + script->index+=8; + aString text; + while(script->buffer[script->index]){ + text+=script->buffer[script->index++]; + } + script->index++; + PlaySound(text,channel,repeat); + return false; +} + +/*! Stop sound + */ +bool EngineWill::OP26(){ + Uint16 channel=GETWORD(script->buffer+script->index+0); + script->index+=2; + StopSound(channel); + return false; +} + +/*! Text without title or caption + */ +bool EngineWill::OP41(){ + script->save=script->index-1; + script->index+=3; + aString text; + while(script->buffer[script->index]){ + if(script->buffer[script->index]=='\\'){ + char escape=script->buffer[++script->index]; + script->index++; + if(escape=='n' || escape=='N'){ + text+="\n"; + } + else{ + LogError("Invalid escape character: \\%c",escape); + } + } + else{ + text+=script->buffer[script->index++]; + } + } + script->index++; + textview->SetVisible(true); + textview->PrintText(text); + state=WILLSTATE_WAITCLICK; + return true; +} + +/*! Text with title (Usually a name) + */ +bool EngineWill::OP42(){ + //Uint16 id=GETWORD(script->buffer+script->index+0); + script->index+=4; + aString title; + while(script->buffer[script->index]){ + title+=script->buffer[script->index++]; + } + script->index++; + aString text; + while(script->buffer[script->index]){ + if(script->buffer[script->index]=='\\'){ + char escape=script->buffer[++script->index]; + script->index++; + if(escape=='n' || escape=='N'){ + text+="\n"; + } + else{ + LogError("Invalid escape character: \\%c",escape); + } + } + else{ + text+=script->buffer[script->index++]; + } + } + + script->index++; + textview->SetVisible(true); + textview->ClearText(); + textview->PrintText(title,text); + state=WILLSTATE_WAITCLICK; + return true; +} + +/*! Load animation + */ +bool EngineWill::OP43(){ + // Parse parameters + script->index+=6; + aString text; + while(script->buffer[script->index]){ + text+=script->buffer[script->index++]; + } + script->index++; + + // Load animation + LogVerbose("Loading animation file: %s",text.c_str()); + if(anim_data){ + for(int i=0;anim_data->frames[i];i++){ + SDL_FreeSurface(anim_data->frames[i]); + } + delete anim_data; + } + anim_data=LoadAnimation(text); + + // Display background frame + SDL_Rect rect; + if(GetImagePosition(anim_data->name,0,&rect)){ + SDL_Surface *frame=anim_data->frames[0]; + if(frame){ + display->Blit(frame,0,&rect); + } + } + return false; +} + +/*! Enable animation in table + */ +bool EngineWill::OP45(){ + Uint16 index=GETWORD(script->buffer+script->index+1); + script->index+=4; + if(anim_data){ + anim_data->visible[index]=true; + } + return false; +} + +/*! Load background + */ +bool EngineWill::OP46(){ + Uint16 x=GETWORD(script->buffer+script->index+0); + Uint16 y=GETWORD(script->buffer+script->index+2); + //Uint8 i=GETBYTE(script->buffer+script->index+8); + script->index+=9; + aString text; + while(script->buffer[script->index]){ + text+=script->buffer[script->index++]; + } + script->index++; + SDL_Surface *image=LoadImage(text); + if(image){ + SDL_Rect r={x,y,image->w,image->h}; + display->Blit(image,&r); + SDL_FreeSurface(image); + } + else{ + LogError("Failed to load background: %s",text.c_str()); + } + return false; +} + +/*! Set background color + */ +bool EngineWill::OP47(){ + Uint8 color=GETBYTE(script->buffer+script->index+0); + script->index+=2; + if(color==0){ + display->Fill(0x000000FF); + } + else{ + LogError("Unknown background color: %d",color); + } + return false; +} + +/*! Load character graphics + */ +bool EngineWill::OP48(){ + Uint8 id=GETBYTE(script->buffer+script->index+0); + //Uint16 x=GETWORD(script->buffer+script->index+1); + //Uint16 y=GETWORD(script->buffer+script->index+3); + //Uint8 index=GETBYTE(script->buffer+script->index+9); + script->index+=10; + aString text; + while(script->buffer[script->index]){ + text+=script->buffer[script->index++]; + } + script->index++; + SDL_Surface *image=0; + if(id>2){ + LogError("Invalid character id: %d",id); + } + else{ + image=LoadMaskedImage(text); + } + if(image){ + //SDL_Rect r={x,y,image->w,image->h}; + overlay[id]->Blit(image); + SDL_FreeSurface(image); + } + else{ + LogError("Failed to load foreground: %s",text.c_str()); + } + return false; +} + +/*! Clear center overlay + */ +bool EngineWill::OP49(){ + Uint16 id=GETWORD(script->buffer+script->index+0); + script->index+=3; + if(id>2){ + LogError("Invalid overlay id: %d",id); + } + else{ + overlay[id]->Free(); + } + return false; +} + +/*! Set transition + * + * The transition timing is very slow and slogs down the game unreasonably + * much. Disabling it seems to work *very* fine, but checking the type might + * be a good idea. + */ +bool EngineWill::OP4A(){ + //Uint8 type=GETBYTE(script->buffer+script->index+0); + Uint16 time=GETWORD(script->buffer+script->index+1); + script->index+=4; + LogVerbose("Transition time: %dmS",time); + //SetTransition(VT_RANDOM,time); + return true; +} + +/*! Add animation + */ +bool EngineWill::OP4B(){ + Uint8 id=GETBYTE(script->buffer+script->index+0); + Uint16 x=GETWORD(script->buffer+script->index+1); + Uint16 y=GETWORD(script->buffer+script->index+3); + Uint16 time=GETWORD(script->buffer+script->index+5); + Uint16 alpha=GETWORD(script->buffer+script->index+9); + script->index+=12; + LogTest("ADD ANIMATION:%d:%d:%d:%d:%d",id,x,y,time,alpha); + return false; +} + +/*! Play animation + */ +bool EngineWill::OP4C(){ + //Uint8 skippable=GETBYTE(script->buffer+script->index+0); + script->index++; + LogTest("PLAY ANIMATION"); + return true; +} + +/*! Load effect + */ +bool EngineWill::OP4D(){ + Uint8 kind=GETBYTE(script->buffer+script->index+0); + Uint8 duration=GETBYTE(script->buffer+script->index+1); + Uint16 factor=GETWORD(script->buffer+script->index+2); + script->index+=5; + if(kind==1){ + LogTest("EFFECT:QUAKE:%dx%d",duration,factor); + } + else if(kind==2){ + LogTest("EFFECT:HEAT:%dx%d",duration,factor); + } + else{ + LogError("Unknown effect: %d",kind); + } + return true; +} + +/*! Disable animation in table + */ +bool EngineWill::OP4F(){ + Uint16 index=GETWORD(script->buffer+script->index+1); + script->index+=4; + if(anim_data){ + anim_data->visible[index]=false; + } + return false; +} + +/*! Load table + * + * Loads table_data which contains graphics for GUI and menues + */ +bool EngineWill::OP50(){ + aString text; + while(script->buffer[script->index]){ + text+=script->buffer[script->index++]; + } + script->index++; + LogVerbose("Loading Will table: %s",text.c_str()); + if(table_data){ + if(table_data->surface){ + SDL_FreeSurface(table_data->surface); + } + delete table_data; + } + table_data=LoadTable(text); + return false; +} + +/*! Select table item (From table_data) + */ +bool EngineWill::OP51(){ + Uint16 flag_click=GETWORD(script->buffer+script->index+0); + Uint16 flag_kind=GETWORD(script->buffer+script->index+2); + selection->SetVisible(false); + textview->SetVisible(false); + table_varclick=flag_click; + table_varkind=flag_kind; + state=WILLSTATE_GUI; + script->index+=5; + return true; +} + +/*! Delay sound (Ignored) + */ +bool EngineWill::OP52(){ + //Uint16 delay=GETWORD(script->buffer+script->index+0); + //LogTest("Delay sound:%d",delay); + script->index+=2; + return false; +} + +/*! Load transparent image + */ +bool EngineWill::OP54(){ + aString text; + while(script->buffer[script->index]){ + text+=script->buffer[script->index++]; + } + script->index++; + if(effect){ + SDL_FreeSurface(effect); + } + if((effect=LoadMaskedImage(text))){ + LogVerbose("Loaded effect image:%s",text.c_str()); + } + else{ + LogError("Failed to load effect:%s",text.c_str()); + } + return false; +} + +/*! Play video + */ +bool EngineWill::OP61(){ + //Uint8 stoppable=GETBYTE(script->buffer+script->index+0); + script->index++; + aString text; + while(script->buffer[script->index]){ + text+=script->buffer[script->index++]; + } + script->index++; + LogVerbose("Loading video: %s",text.c_str()); +LogTest("VIDEO:%s",text.c_str()); + QueueVideo(text); + return true; +} + +/*! Show character info (Not supported) + */ +bool EngineWill::OP64(){ + //Uint8 index=GETBYTE(script->buffer+script->index+0); + //Uint8 size=GETBYTE(script->buffer+script->index+1); + //Uint8 rotation=GETBYTE(script->buffer+script->index+2); + script->index+=4; + LogTest("Show character info"); + return false; +} + +/*! Set background size and position + */ +bool EngineWill::OP68(){ + //Sint16 size=GETBYTE(script->buffer+script->index+0); + //Sint16 xbase=GETBYTE(script->buffer+script->index+2); + //Sint16 ybase=GETBYTE(script->buffer+script->index+4); + script->index+=7; + return false; +} + +/*! Add overlay + */ +bool EngineWill::OP73(){ + Uint16 x=GETWORD(script->buffer+script->index+0); + Uint16 y=GETWORD(script->buffer+script->index+2); + script->index+=9; + aString text; + while(script->buffer[script->index]){ + text+=script->buffer[script->index++]; + } + script->index++; + LogTest("ADD OVERLAY:%d:%d:%s",x,y,text.c_str()); + return false; +} + +/*! Clear overlay + */ +bool EngineWill::OP74(){ + Uint16 index=GETWORD(script->buffer+script->index+0); + script->index+=2; + LogTest("CLEAR OVERLAY:%d",index); + return false; +} + +/*! Delay execution + */ +bool EngineWill::OP82(){ + //Uint16 delay=GETWORD(script->buffer+script->index+0); + script->index+=3; + //LogTest("OP82:DELAY:%d",delay); + //SDL_Delay(delay); + return true; +} + +/*! Load game + */ +bool EngineWill::OP83(){ + script->index++; + EventGameDialog(VD_LOAD); + return true; +} + +/*! New game + */ +bool EngineWill::OP84(){ + script->index++; +LogTest("OP84:NEW:SAVE"); + return true; +} + +/*! Configuration screen + */ +bool EngineWill::OP8B(){ + script->index++; + EventGameDialog(VD_OPTIONS); + return true; +} + +/*! Quick load (Autoload save 998) + */ +bool EngineWill::OPE2(){ + script->index++; + EventLoad(998); + return false; +} + +/*! Text ... + */ +bool EngineWill::OPB6(){ + Uint16 id=GETWORD(script->buffer+script->index+0); + script->index+=2; + aString text; + while(script->buffer[script->index]){ + text+=script->buffer[script->index++]; + } + script->index++; + LogTest("OPB6:%d:%s",id,text.c_str()); + return false; +} + +/*! Clear right overlay + */ +bool EngineWill::OPB8(){ + Uint16 id=GETWORD(script->buffer+script->index+0); + script->index+=3; + if(id>2){ + LogError("Invalid overlay id: %d",id); + } + else{ + overlay[id]->Free(); + } + return false; +} + +/*! End of file + */ +bool EngineWill::OPFF(){ + LogTest("END OF FILE"); + return true; +} + +/*! Unknown OP + */ +bool EngineWill::OPXX(int Length){ + script->index+=Length; + return false; +} + + diff --git a/engines/vileVN/will/will.h b/engines/vileVN/will/will.h new file mode 100644 index 0000000000..d982effb60 --- /dev/null +++ b/engines/vileVN/will/will.h @@ -0,0 +1,147 @@ +/*! \class EngineWill + * \brief Will game engine + * + * This implementation was ported from VNMV (http://code.google.com/p/vnvm/) + * with the concent of its author, soywiz. Thank you! + */ +#ifndef _WILL_H_ +#define _WILL_H_ + +#include "../engine/evn.h" + +#define GETBYTE(B) ((B)[0]) +#define GETWORD(B) ((B)[0]|((B)[1]<<8)) +#define GETDWORD(B) ((B)[0]|((B)[1]<<8)|((B)[2]<<16)|((B)[3]<<24)) + +struct WILLTABLE { + SDL_Surface *surface; //!< Decoded graphics + Uint32 flags[0xFF]; //!< Unknown binary blobs + Uint8 keymap[0x12][0x10]; //!< Maps keyboard input + Uint32 count; //!< Have no idea +}; + +struct WILLANIMATION { + uString name; //!< Name of WIP graphic file + SDL_Surface **frames; //!< Animation frames + bool visible[100]; //!< Visibility for each frame + Uint16 entries[100][402]; //!< Unknown binary blobs +}; + +enum WILLSTATES { + WILLSTATE_NORMAL, //!< Process input script + WILLSTATE_GUI, //!< Will gui subsystem + WILLSTATE_CHOICE, //!< Wait for user to click a selection + WILLSTATE_WAITCLICK //!< Wait for user to click +}; + +class EngineWill : public EngineVN { + private: + // Script data + struct SCRIPT { + uString name; //!< Name of current script + Uint8 *buffer; //!< Script data + unsigned int length; //!< Length of script data + unsigned int index; //!< Index of binary script buffer + unsigned int save; //!< Position for savegame + SCRIPT *nextptr; //!< Pointer to stacked parent + }*script; + DVector vars; //!< Holds values + WILLSTATES state; //!< Current state + unsigned int ticks_stamp; //!< Time of last tick update + unsigned int ticks_value; //!< Ticks left in timer + + // Will stuff + Stringlist jumptable; //!< Jumptable for selections + SDL_Surface *effect; //!< Effectsurface + WILLANIMATION *anim_data; //!< Holds animation data + WILLTABLE *table_data; //!< Holds table data + int table_mouseindex; //!< Index for mouse hovering + int table_varclick; //!< Variable to register index in + int table_varkind; //!< Variable to register kind in + uString bgname; //!< Name of current bg resource + + // Opcode handlers + bool OP01(); //!< Conditional jump + bool OP02(); //!< Decision box + bool OP03(); //!< Calculus + bool OP04(); //!< Halt execution + bool OP05(); //!< Wait for timer + bool OP06(); //!< Absolute jump + bool OP07(); //!< Load script + bool OP08(); //!< Set text size + bool OP09(); //!< Call script + bool OP0A(); //!< Return from called script + bool OP0B(); //!< Set timer + bool OP0C(); //!< Decrement timer + bool OP21(); //!< Play music + bool OP22(); //!< Stop music + bool OP23(); //!< Play voice + bool OP25(); //!< Play sound + bool OP26(); //!< Stop sound + bool OP41(); //!< Text .. + bool OP42(); //!< Text .. + bool OP43(); //!< Load table file + bool OP45(); //!< Set table item + bool OP4A(); //!< Set transition + bool OP4B(); //!< Add animation + bool OP4C(); //!< Play animation + bool OP4D(); //!< Add effect + bool OP4F(); //!< Unset table item + bool OP50(); //!< Load table item + bool OP51(); //!< Pick table item + bool OP52(); //!< Delay sound + bool OP54(); //!< Load transparent image + bool OP61(); //!< Play video + bool OPB6(); //!< Text .. + bool OPFF(); //!< EOF + bool OP46(); //!< Set background image + bool OP47(); //!< Set background color + bool OP48(); //!< Display character image + bool OP49(); //!< Clear overlay + bool OP64(); //!< Show character info + bool OP68(); //!< Background position + bool OP73(); //!< Add overlay + bool OP74(); //!< Clear layer + bool OP82(); //!< Fixed delay + bool OP83(); //!< New game load + bool OP84(); //!< Name game save + bool OP8B(); //!< Show config + bool OPB8(); //!< Clear layer + bool OPE2(); //!< Quickload + bool OPXX(int Size); //!< Skip unknown/irrelevant opcode + protected: + // Widgets + Widget *display; //!< Widget for showing base graphics + Widget *overlay[3]; //!< Widget for showing characters + Textview *textview; //!< Textview display + Selection *selection; //!< Simple text choices + public: + EngineWill(int Width,int Height); + ~EngineWill(); + + // Game interface + WILLTABLE *LoadTable(uString Name); + WILLANIMATION *LoadAnimation(uString Name); + SDL_Surface *LoadMaskedImage(uString Name); + SDL_Surface **LoadMaskedAnimation(uString Name); + bool GetImagePosition(uString Name,Uint8 Index,SDL_Rect *Rect); + bool LoadWillScript(uString Script); + bool Jump(unsigned int Position); + bool Running(); + void Stop(); + + // Eventhandlers + virtual bool EventGameTick(); + virtual bool EventGameProcess(); + virtual bool EventLoad(int Index); + virtual bool EventSave(int Index); + virtual void EventSelect(int Selection); + virtual void EventGameDialog(VN_DIALOGS Dialog); + virtual bool EventBackgroundMouseMove(int X,int Y); + virtual bool EventBackgroundMouseLeftDown(int X,int Y); + virtual bool EventBackgroundMouseRightDown(int X,int Y); + +}; + +#endif + diff --git a/engines/vileVN/will/yume/yume.cpp b/engines/vileVN/will/yume/yume.cpp new file mode 100644 index 0000000000..f3b8e10164 --- /dev/null +++ b/engines/vileVN/will/yume/yume.cpp @@ -0,0 +1,55 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "yume.h" + +YumeMiruKusuri::YumeMiruKusuri(uString Path) : EngineWill(800,600) { + // Add resources + AddBGM(new ArchiveWillARC(Path+"bgm.arc")); + AddVoices(new ArchiveWillARC(Path+"voice.arc")); + AddSE(new ArchiveWillARC(Path+"se.arc")); + AddScripts(new ArchiveWillARC(Path+"rio.arc")); + AddImages(new ArchiveWillARC(Path+"chip.arc")); + AddOther(new ArchiveWillARC(Path+"chip.arc")); + AddVideo(new ArchiveFiles(Path+"a_ed.dat")); + AddVideo(new ArchiveFiles(Path+"m_ed.dat")); + AddVideo(new ArchiveFiles(Path+"n_ed.dat")); + AddVideo(new ArchiveFiles(Path+"op.dat")); + + // Configure textview + DestroyWidget(textview); + textview=new YumeTextview(this); + AddWidget(textview,VL_TEXTVIEW); + + // Configure textview + //selection->Move(100,396); + //selection->Resize(440,70); + selection->Resize(640/3,480/3); + selection->Move(640/3,480/3); + selection->SetAlignment(HA_CENTER,VA_CENTER); + + // Show main menu + EventGameDialog(VD_TITLE); +} + +const uString YumeMiruKusuri::NativeID(){ + return "Yume"; +} + +const uString YumeMiruKusuri::NativeName(){ + return "Yume Miru Kusuri"; +} + + diff --git a/engines/vileVN/will/yume/yume.h b/engines/vileVN/will/yume/yume.h new file mode 100644 index 0000000000..8fba1a7e51 --- /dev/null +++ b/engines/vileVN/will/yume/yume.h @@ -0,0 +1,23 @@ +/*! \class Yume MiruKusuri + * \brief Yume Miru Kusuri implementation + */ + +#ifndef _YUMEMIRUKUSURI_H_ +#define _YUMEMIRUKUSURI_H_ + +#include "../will.h" +#include "yumetv.h" + +class YumeMiruKusuri : public EngineWill { + private: + public: + YumeMiruKusuri(uString Path); + + // Overrides + virtual const uString NativeID(); + virtual const uString NativeName(); +}; + +#endif + + diff --git a/engines/vileVN/will/yume/yumetv.cpp b/engines/vileVN/will/yume/yumetv.cpp new file mode 100644 index 0000000000..f5e85cb4b4 --- /dev/null +++ b/engines/vileVN/will/yume/yumetv.cpp @@ -0,0 +1,167 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "yumetv.h" +#include "yume.h" + +YumeTextview::YumeTextview(YumeMiruKusuri *Engine) : Textview(Engine) { + SDL_Rect rect; + //SetTextPosition(0,0,800,165); + //MoveDialog(0,0); + //Resize(800,165); + w_save=0; + w_load=0; + w_skip=0; + w_auto=0; + w_history=0; + w_repeat=0; + w_thing=0; + header=0; + SDL_Surface **winbase=Engine->LoadMaskedAnimation("winbase0"); + if(winbase){ + int ypos=0; + for(int i=0;winbase[i];i++){ + if(Engine->GetImagePosition("winbase0",i,&rect)){ + if(i==YUMETV_BACKGROUND){ + ypos=Engine->NativeHeight()-rect.h; + int textx=30; + int texty=60; + int textw=700; + int texth=100; + SetTextPosition(textx,texty,textw,texth); + MoveDialog(rect.x,ypos); + Resize(rect.w,rect.h); + Set(winbase[i]); + } + if(i==YUMETV_BUTTON_QSAVE){ + // Configure widgets + rect.y+=ypos; + w_save=new ValueButton(rect); + w_save->SetState(WS_NORMAL,winbase[i+21],0,winbase[i+0],0); + w_save->SetState(WS_HOVER,winbase[i+21],0,winbase[i+7],0); + w_save->SetState(WS_SELECT,winbase[i+21],0,winbase[i+14],0); + AddWidget(w_save); + } + if(i==YUMETV_BUTTON_QLOAD){ + // Configure widgets + rect.y+=ypos; + w_load=new BitmapButton(rect); + w_load->SetState(WS_NORMAL,winbase[i],0); + w_load->SetState(WS_HOVER,winbase[i+7],0); + w_load->SetState(WS_SELECT,winbase[i+14],0); + AddWidget(w_load); + } + if(i==YUMETV_BUTTON_SKIP){ + // Configure widgets + rect.y+=ypos; + w_skip=new ValueButton(rect); + w_skip->SetState(WS_NORMAL,winbase[i+20],0,winbase[i+0],0); + w_skip->SetState(WS_HOVER,winbase[i+20],0,winbase[i+7],0); + w_skip->SetState(WS_SELECT,winbase[i+20],0,winbase[i+14],0); + AddWidget(w_skip); + } + if(i==YUMETV_BUTTON_AUTO){ + // Configure widgets + rect.y+=ypos; + w_auto=new ValueButton(rect); + w_auto->SetState(WS_NORMAL,winbase[i+20],0,winbase[i+0],0); + w_auto->SetState(WS_HOVER,winbase[i+20],0,winbase[i+7],0); + w_auto->SetState(WS_SELECT,winbase[i+20],0,winbase[i+14],0); + AddWidget(w_auto); + } + if(i==YUMETV_BUTTON_HISTORY){ + // Configure widgets + rect.y+=ypos; + w_history=new BitmapButton(rect); + w_history->SetState(WS_NORMAL,winbase[i],0); + w_history->SetState(WS_HOVER,winbase[i+7],0); + w_history->SetState(WS_SELECT,winbase[i+14],0); + AddWidget(w_history); + } + + if(i==YUMETV_BUTTON_REPEAT){ + // Configure widgets + rect.y+=ypos; + w_repeat=new BitmapButton(rect); + w_repeat->SetState(WS_NORMAL,winbase[i],0); + w_repeat->SetState(WS_HOVER,winbase[i+7],0); + w_repeat->SetState(WS_SELECT,winbase[i+14],0); + AddWidget(w_repeat); + } + if(i==YUMETV_BUTTON_THING){ + // Configure widgets + rect.y+=ypos; + w_thing=new BitmapButton(rect); + w_thing->SetState(WS_NORMAL,winbase[i],0); + w_thing->SetState(WS_HOVER,winbase[i+7],0); + w_thing->SetState(WS_SELECT,winbase[i+14],0); + AddWidget(w_thing); + } + if(i==YUMETV_BUTTON_HEADER){ + // Background for displaying the name + header=new Printer(pos.x+4,pos.y, + winbase[i]->w,winbase[i]->h); + header->Blit(winbase[i]); + AddWidget(header); + } + } + SDL_FreeSurface(winbase[i]); + } + delete [] winbase; + } +} + +YumeTextview::~YumeTextview(){ +} + +bool YumeTextview::InputOk(Widget *Object){ + bool retval=false; + if(Object==w_load){ + ((YumeMiruKusuri*)engine)->EventLoad(998); + retval=true; + } + else if(Object==w_save){ + ((YumeMiruKusuri*)engine)->EventSave(998); + w_save->SetValue(true); + retval=true; + } + else if(Object==w_history){ + ((YumeMiruKusuri*)engine)->EventGameDialog(VD_LOG); + } + else if(Object==w_skip){ + ((YumeMiruKusuri*)engine)->SetSkipmode(true); + w_skip->SetValue(true); + retval=true; + } + return retval; +} + +void YumeTextview::PrintText(uString Title,uString Text){ + if(header){ + header->Clear(); + header->Print(Title,0); + header->SetVisible(true); + } + Textview::PrintText(Text); +} + +void YumeTextview::PrintText(uString Text){ + if(header){ + header->SetVisible(false); + } + Textview::PrintText(Text); +} + + diff --git a/engines/vileVN/will/yume/yumetv.h b/engines/vileVN/will/yume/yumetv.h new file mode 100644 index 0000000000..f3d50388fe --- /dev/null +++ b/engines/vileVN/will/yume/yumetv.h @@ -0,0 +1,41 @@ +#ifndef _YUMETV_H_ +#define _YUMETV_H_ + +#include "../../dialogs/textview.h" + +#define YUMETV_BACKGROUND 0 +#define YUMETV_BUTTON_QSAVE 1 +#define YUMETV_BUTTON_QLOAD 2 +#define YUMETV_BUTTON_SKIP 3 +#define YUMETV_BUTTON_AUTO 4 +#define YUMETV_BUTTON_HISTORY 5 +#define YUMETV_BUTTON_REPEAT 6 +#define YUMETV_BUTTON_THING 7 +#define YUMETV_BUTTON_HEADER 25 + +class YumeMiruKusuri; + +class YumeTextview : public Textview { + private: + // Widgets + ValueButton *w_save; + BitmapButton *w_load; + ValueButton *w_skip; + ValueButton *w_auto; + BitmapButton *w_history; + BitmapButton *w_repeat; + BitmapButton *w_thing; + Printer *header; + public: + YumeTextview(YumeMiruKusuri *Engine); + ~YumeTextview(); + + void PrintText(uString Title,uString Text); + void PrintText(uString Text); + + // Event overrides + virtual bool InputOk(Widget *Object); +}; + +#endif + diff --git a/engines/vileVN/windy/mayclub/mayclub.cpp b/engines/vileVN/windy/mayclub/mayclub.cpp new file mode 100644 index 0000000000..aab85efa91 --- /dev/null +++ b/engines/vileVN/windy/mayclub/mayclub.cpp @@ -0,0 +1,567 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "mayclub.h" + +Mayclub::Mayclub(uString Path) : EngineWindy(640,480) { + // Set defaults + sbuffer0=0; + sbuffer1=0; + sbuffer2=0; + + // Load english censorship patches (Optional) + //AddScripts(new ArchiveFiles(Path+"A04.S")); + //AddScripts(new ArchiveFiles(Path+"AH1.S")); + //AddScripts(new ArchiveFiles(Path+"OPEN.S")); + + // Load english legacy patches + AddScripts(new ArchiveFiles(Path+"B03.S")); + AddScripts(new ArchiveFiles(Path+"B03B.S")); + AddScripts(new ArchiveFiles(Path+"B06.S")); + AddScripts(new ArchiveFiles(Path+"B07.S")); + AddScripts(new ArchiveFiles(Path+"BE2.S")); + AddScripts(new ArchiveFiles(Path+"G15.S")); + + // Load english legacy resources + AddScripts(new ArchiveWindy(Path+"may0.dat")); + AddOther(new ArchiveFiles(Path+"memory.dat")); + + // Load new japanese resources + AddImages(new ArchiveS21(Path+"cg/graphic.pak")); + AddSE(new ArchiveS21(Path+"se/se.pak")); + AddVoices(new ArchiveS21(Path+"voice/voice.pak")); + AddBGM(new ArchiveFiles(Path+"wave/*.wav")); + + // Create and assign specialized textview object + w_tv=new MCTextview(this); + AddWidget(w_tv,VL_TEXTVIEW); + + // Create and assign voice syncronizer + whisper=new MCWhisper(this); + whisper->AddResource(new ArchiveS21(Path+"snr/Scenario.pak")); + + // Preload graphics for selection + char bbitmap[32]; + char bmask[32]; + for(int i=1;i<5;i++){ + sprintf(bbitmap,"SEL2_%d.bet",i); + sprintf(bmask,"SEL2_%d_.bet",i); + SDL_Surface *selbitmap=LoadImage(bbitmap); + SDL_Surface *selmask=LoadImage(bmask); + if(selbitmap && selmask){ + sselection[i-1]=EDL_MaskSurface(selbitmap,selmask,0); + SDL_FreeSurface(selmask); + SDL_FreeSurface(selbitmap); + } + else{ + LogError("Failed to load selection graphics: SEL2_%d.bet",i); + sselection[i-1]=0; + } + } + + // Map cgresources + int i=0; + RegisterCG(i++,"a03"); + RegisterCG(i++,"a04"); + RegisterCG(i++,"a06"); + RegisterCG(i++,"a07"); + RegisterCG(i++,"a08"); + RegisterCG(i++,"a09"); + RegisterCG(i++,"a10"); + RegisterCG(i++,"b12"); + RegisterCG(i++,"b13"); + RegisterCG(i++,"b14"); + RegisterCG(i++,"b16"); + RegisterCG(i++,"b17a"); + RegisterCG(i++,"b17b"); + RegisterCG(i++,"b17c"); + RegisterCG(i++,"b18"); + RegisterCG(i++,"b19"); + RegisterCG(i++,"c21"); + RegisterCG(i++,"c22a"); + RegisterCG(i++,"c22b"); + RegisterCG(i++,"c23"); + RegisterCG(i++,"c24"); + RegisterCG(i++,"c25"); + RegisterCG(i++,"c26"); + RegisterCG(i++,"d28"); + RegisterCG(i++,"d29"); + RegisterCG(i++,"d30a"); + RegisterCG(i++,"d30b"); + RegisterCG(i++,"d31"); + RegisterCG(i++,"d32a"); + RegisterCG(i++,"d32b"); + RegisterCG(i++,"d33a"); + RegisterCG(i++,"d33b"); + RegisterCG(i++,"d34"); + RegisterCG(i++,"e36"); + RegisterCG(i++,"e37"); + RegisterCG(i++,"e38a"); + RegisterCG(i++,"e38b"); + RegisterCG(i++,"e39"); + RegisterCG(i++,"e40"); + RegisterCG(i++,"e41"); + RegisterCG(i++,"f36"); + RegisterCG(i++,"f37"); + RegisterCG(i++,"f38"); + RegisterCG(i++,"f39"); + RegisterCG(i++,"f40"); + RegisterCG(i++,"g42"); + RegisterCG(i++,"g43a"); + RegisterCG(i++,"g43b"); + RegisterCG(i++,"g43c"); + + // Map story resources + i=0; + RegisterScene(i++,"ah1"); + RegisterScene(i++,"ah2"); + RegisterScene(i++,"bh1"); + RegisterScene(i++,"bh2"); + RegisterScene(i++,"ch1"); + RegisterScene(i++,"dh1"); + RegisterScene(i++,"dh2"); + RegisterScene(i++,"eh1"); + RegisterScene(i++,"eh2"); + RegisterScene(i++,"ee1"); // Double check + RegisterScene(i++,"gh1"); + RegisterScene(i++,"hh1"); + RegisterScene(i++,"hh2"); + RegisterScene(i++,"ih1"); + RegisterScene(i++,"ih2"); + + // Load common routines + LoadWindyRoutines("MAY_SUB.S"); + + // Load main menu + main=new MCMain(this); + AddWidget(main,VL_DIALOG); + EventGameDialog(VD_TITLE); +} + +Mayclub::~Mayclub(){ + // Free graphics + for(int i=0;i<4;i++){ + if(sselection[i]){ + SDL_FreeSurface(sselection[i]); + } + } + + // Delete buffers + if(sbuffer0){ + SDL_FreeSurface(sbuffer0); + sbuffer0=0; + } + if(sbuffer1){ + SDL_FreeSurface(sbuffer1); + sbuffer1=0; + } + if(sbuffer2){ + SDL_FreeSurface(sbuffer2); + sbuffer2=0; + } +} + +bool Mayclub::EventBackgroundMouseRightUp(int X,int Y){ + // Show options dialog + w_tv->SetVisible(!w_tv->GetVisible()); + return true; +} + +void Mayclub::EventTextMode(Uint16 Mode,Uint16 X,Uint16 Y, + Uint16 Width,Uint16 Height,Uint16 Flag){ + // Check for valid textmodes + int x=0,y=0,w=0,h=0; + if(Mode==0x0003 || Mode==0x000B){ + if(X==0x0002 && Y==0x0013){ + // Normal text mode + x=80; + y=384; + w=480; + h=84; + } + else{ + LogDebug("Unknown text position for mayclub: %d(%d,%d)",Mode,X,Y); + } + } + else{ + LogError("Unknown textmode for mayclub: %d(%d,%d)",Mode,X,Y); + } + + // Change textmode if applicable + if(x || y || w || h){ + w_tv->ClearText(); + w_tv->SetTextPosition(x,y,w,h); + } +} + +/*! \brief Override routines to match updated gui + * \param Address Address of external routine + * \return True if the call was handled internally + * + * In addition to accommodating the changes in gui, we also override the + * blitting routines to avoid meaningless loops (Ie. built-in graphical + * transition effects). + */ +bool Mayclub::EventExternal(Uint16 Address){ + bool retval=false; + + // Override slow looping routines + if(Address==0x4100){ + w_bg->Blit(sbuffer1); + retval=true; + } + else if(Address==0x4104){ + if(!sbuffer1){ + sbuffer1=EDL_CreateSurface(NativeWidth(),NativeHeight()); + } + SDL_Rect full={0,0,sbuffer1->w,sbuffer1->h}; + boxRGBA(sbuffer1,0,0,full.w,full.h,0,0,0,0xFF); + w_bg->Blit(sbuffer1); + retval=true; + } + else if(Address==0x4110){ + w_bg->Blit(sbuffer1); + retval=true; + } + else if(Address==0x4114){ + w_bg->Blit(sbuffer2); + retval=true; + } + else if(Address==0x4562){ + w_bg->Blit(sbuffer1); + retval=true; + } + else if(Address==0x4B52){ + w_bg->Blit(sbuffer1); + w_bg->Blend(sbuffer2); + retval=true; + } + + // Override mayclub specific gui routines + else if(Address==0x4144){ + // Update time and date display + Uint16 month=vars.GetUint16(0x0127); + Uint16 day=vars.GetUint16(0x0128); + Uint16 time=vars.GetUint16(0x0129); + Uint16 dayofweek=vars.GetUint16(0x012B); + MCTextview *w_mctv=(MCTextview*)w_tv; + w_mctv->SetTime(month,day,time,dayofweek); + retval=true; + } + else if(Address==0x415C){ + // Update credits display + Uint16 credits=vars.GetUint16(0x0126); + MCTextview *w_mctv=(MCTextview*)w_tv; + w_mctv->SetTickets(credits); + retval=true; + } + + // Report unknown adresses (Debugging only) + else if(Address!=0x4120 && + Address!=0x412C && + Address!=0x4130 && + Address!=0x4134 && + Address!=0x4140 && + Address!=0x4148 && + Address!=0x414C && + Address!=0x48C0 && + Address!=0x60B0){ + LogDebug("Calling mayclub external: 0x%04x",Address); + } + return retval; +} + +void Mayclub::EventGameDialog(VN_DIALOGS Dialog){ + if(Dialog==VD_TITLE){ + DestroyLayer(VL_CHOICES); + StopMusic(); + StopSound(); + main->SetVisible(true); + PlayMusic("01"); + } + else if(Dialog==VD_SAVE){ + AddWidget(new MCSave(this),VL_DIALOG); + } + else if(Dialog==VD_LOAD){ + AddWidget(new MCLoad(this),VL_DIALOG); + } + else if(Dialog==VD_LOG){ + AddWidget(new MCBack(this,w_tv),VL_DIALOG); + } + else if(Dialog==VD_CREDITS){ + // Scroll staffroll + SDL_Surface *surface=LoadImage("STAFF.BET"); + if(surface){ + Sequences->RollPaddedVertical(surface); + Sequences->LogoRandom(0,0,0); + SDL_FreeSurface(surface); + } + else{ + LogError("Failed to load staffroll"); + } + + // Fade in titlescreen + if(main){ + SDL_Rect dst={0,0,NativeWidth(),NativeHeight()}; + AddAnimation(new Fade(dst,main->GetSurface(),dst,5000)); + } + } + else{ + EngineVN::EventGameDialog(Dialog); + } +} + +void Mayclub::EventNew(){ + // Preset values + EngineWindy::EventNew(); + vars.SetUint16(0x0126,0x0010); // Credits + vars.SetUint16(0x0127,0x0002); // Month + vars.SetUint16(0x0128,0x0010); // Day + vars.SetUint16(0x0129,0x0002); // Time of day + vars.SetUint16(0x0206,0xffff); // Cached background + vars.SetUint16(0x020c,0xffff); // Cached foreground + + // Prepare textview + MCTextview *w_mctv=(MCTextview*)w_tv; + w_mctv->SetTickets(0); + w_mctv->SetTime(2,16,0,3); + + // Load initialization code + LoadWindyScript("OPEN.S",0x0245); + SetTransition(); +} + +bool Mayclub::EventSave(int Index){ + bool retval=EngineWindy::EventSave(Index); + if(retval){ + Savegame *save=new Savegame(NativeID(),Index); + save->Read(); + if(sbuffer1){ + save->SaveSurface("screen-background",sbuffer1); + } + } + return retval; +} + +bool Mayclub::EventLoad(int Index){ + bool retval=EngineWindy::EventLoad(Index); + if(retval){ + // Load mayclub specific data + Savegame *load=new Savegame(NativeID(),Index); + load->Read(); + SDL_Surface *tmps; + if(load->LoadSurface("screen-background",&tmps)){ + if(sbuffer1){ + SDL_FreeSurface(sbuffer1); + } + sbuffer1=tmps; + } + delete load; + + // Update credits, time and date display + Uint16 month=vars.GetUint16(0x0127); + Uint16 day=vars.GetUint16(0x0128); + Uint16 time=vars.GetUint16(0x0129); + Uint16 dayofweek=vars.GetUint16(0x012B); + Uint16 credits=vars.GetUint16(0x0126); + MCTextview *w_mctv=(MCTextview*)w_tv; + w_mctv->SetTime(month,day,time,dayofweek); + w_mctv->SetTickets(credits); + + // Make sure the mainscreen is hidden + main->SetVisible(false); + } + return retval; +} + +uString Mayclub::GetImagename(uString Imagename){ + uString tmp=EDL_Searchname(Imagename); + if(tmp=="z65y") return "z65n"; + else return Imagename; +} + +bool Mayclub::LoadGraphics(uString Resource,Uint16 Index,Uint16 Type){ + // Load image according to format + bool retval; + uString resource=GetImagename(Resource); + SDL_Surface *surface=LoadImage(resource.c_str()); + if((retval=surface)){ + // Force off alpha?? + SDL_SetAlpha(surface,0,0xFF); + + // Get name of mask bitmap + uString name=resource; + uString ext; + for(int i=name.length();i>0;i--){ + if(name[i-1]=='.'){ + ext=name.substr(i-1); + name=name.substr(0,i-1); + break; + } + else if(name[i-1]=='/' || name[i-1]=='\\'){ + break; + } + } + + // Mask image if possible + name+="_"; + name+=ext; + SDL_Surface *mask=LoadImage(name); + if(mask){ + SDL_Surface *tmp=EDL_MaskSurface(surface,mask,0); + SDL_FreeSurface(mask); + SDL_FreeSurface(surface); + surface=tmp; + } + + // Sent to destination + if(Index==0x0000){ + if(sbuffer0){ + SDL_FreeSurface(sbuffer0); + } + sbuffer0=surface; + } + else if(Index==0x0001){ + if(sbuffer1){ + SDL_FreeSurface(sbuffer1); + } + sbuffer1=surface; + } + else if(Index==0x0002){ + if(sbuffer2){ + SDL_FreeSurface(sbuffer2); + } + sbuffer2=surface; + } + else{ + LogError("Unknown target surface: %04x (%d)",Index,Type); + SDL_FreeSurface(surface); + } + } + else{ + LogError("Failed to load surface: %s",Resource.c_str()); + } + return retval; +} + +void Mayclub::FillGraphics(Uint16 Index){ + int w=NativeWidth(); + int h=NativeHeight(); + SDL_Surface *source=EDL_CreateSurface(w,h); + boxRGBA(source,0,0,w,h,0,0,0,0xFF); + if(Index==0x0000){ + if(sbuffer0){ + SDL_FreeSurface(sbuffer0); + } + sbuffer0=source; + } + else if(Index==0x0001){ + if(sbuffer1){ + SDL_FreeSurface(sbuffer1); + } + sbuffer1=source; + } + else if(Index==0x0002){ + if(sbuffer2){ + SDL_FreeSurface(sbuffer2); + } + sbuffer2=source; + } + else{ + LogError("Invalid fill target: 0x%x",Index); + SDL_FreeSurface(source); + } +} + +const uString Mayclub::NativeID(){ + return "May"; +} + +const uString Mayclub::NativeName(){ + return "Mayclub VR Dating SX"; +} + +bool Mayclub::PlayMusic(uString Name){ + // Assert prefix + bool retval=true; + if(Name.length()==1){ + Name=uString("0")+Name; + } + if(Name.length() && Name[0]!='n' && Name[0]!='N'){ + Name=uString("n")+Name; + } + + // Drop postfix if any + for(int i=Name.length();i>0;i--){ + if(Name[i]=='_'){ + Name=Name.substr(0,i); + break; + } + } + + // Parse a basename + uString base=Name; + for(int i=Name.length();i>0;i--){ + if(base[i]=='.'){ + base=base.substr(0,i); + break; + } + } + + // Try various name combinations + if(!EngineVN::QueueMusic(Name)){ + Name=base; + Name+="_88p.wav"; + if(!EngineVN::QueueMusic(Name)){ + Name=base; + Name+="_88.wav"; + if(!EngineVN::QueueMusic(Name)){ + Name=base; + Name+="_55.wav"; + if(!EngineVN::QueueMusic(Name)){ + retval=false; + } + } + } + } + return retval; +} + +Widget *Mayclub::LoadSelection(Stringlist Strings){ + int selcount=Strings.GetCount(); + if(selcount>3){ + selcount=3; + } + if(selcount>=0 && sselection[selcount]){ + // Assign best-effort bitmap + Selection *seldialog=new Selection(this); + int gw=NativeWidth(); + int gh=NativeHeight(); + seldialog->SetAlignment(HA_CENTER,VA_CENTER); + seldialog->Resize(sselection[selcount]->w,sselection[selcount]->h); + seldialog->Move((gw-sselection[selcount]->w)/2, + (gh-sselection[selcount]->h)/2); + seldialog->Set(sselection[selcount],0,0); + seldialog->SetText(&Strings); + seldialog->SetFocusItem(0); + return seldialog; + } + else{ + LogError("Failed to load selection cache: %d",selcount); + return 0; + } +} + + diff --git a/engines/vileVN/windy/mayclub/mayclub.h b/engines/vileVN/windy/mayclub/mayclub.h new file mode 100644 index 0000000000..94a6d8fe6f --- /dev/null +++ b/engines/vileVN/windy/mayclub/mayclub.h @@ -0,0 +1,57 @@ +/*! \class Mayclub + * \brief Uses the crowd engine to stage a XChange 3 game + */ +#ifndef _MAYCLUB_H_ +#define _MAYCLUB_H_ + +#include "../windy.h" +#include "mcwhisper.h" +#include "mcload.h" +#include "mcsave.h" +#include "mcmain.h" +#include "mcalbum.h" +#include "mctv.h" +#include "mcback.h" + +class Mayclub : public EngineWindy { + private: + // Graphic buffers + SDL_Surface *sbuffer0; + SDL_Surface *sbuffer1; + SDL_Surface *sbuffer2; + + // Cached selection graphics + SDL_Surface *sselection[4]; + + // Cached main menu + MCMain *main; + + // Helper functions + uString GetImagename(uString Imagename); + public: + Mayclub(uString Path); + ~Mayclub(); + + // Special windy events + virtual void EventTextMode(Uint16 Mode,Uint16 X,Uint16 Y, + Uint16 Width,Uint16 Height,Uint16 Flag); + virtual bool EventExternal(Uint16 Address); + + // Windy methods + virtual bool LoadGraphics(uString Name,Uint16 Index,Uint16 Type); + virtual void FillGraphics(Uint16 Index); + virtual Widget *LoadSelection(Stringlist Strings); + + // Overrides + virtual const uString NativeID(); + virtual const uString NativeName(); + virtual bool PlayMusic(uString Name); + virtual void EventGameDialog(VN_DIALOGS Dialog); + virtual bool EventSave(int Index); + virtual bool EventLoad(int Index); + virtual void EventNew(); + virtual bool EventBackgroundMouseRightUp(int X,int Y); +}; + +#endif + diff --git a/engines/vileVN/windy/mayclub/mcalbum.cpp b/engines/vileVN/windy/mayclub/mcalbum.cpp new file mode 100644 index 0000000000..9d1231b57d --- /dev/null +++ b/engines/vileVN/windy/mayclub/mcalbum.cpp @@ -0,0 +1,434 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "mcalbum.h" +#include "mayclub.h" + +MCAlbum::MCAlbum(Mayclub *Engine) : DialogBase(Engine,true){ + // Load main menu graphics + SDL_Surface *salbum2=Engine->LoadImage("album2.bet"); + SDL_Surface *palbum1=Engine->LoadImage("album1.bet"); + SDL_Surface *malbum1=Engine->LoadImage("album1_.bet"); + SDL_Surface *pparts=Engine->LoadImage("albumparts.bet"); + SDL_Surface *mparts=Engine->LoadImage("albumparts_.bet"); + if(pparts && mparts && salbum2 && palbum1 && malbum1){ + // Fade in background graphics + SDL_Rect rfull={0,0,salbum2->w,salbum2->h}; + Move(rfull); + Engine->AddAnimation(new Fade(rfull,salbum2,rfull,1000)); + SDL_Surface *salbum1=EDL_MaskSurface(palbum1,malbum1,0); + EDL_BlitSurface(salbum1,0,salbum2,0); + Engine->AddAnimation(new Fade(rfull,salbum2,rfull,1000)); + Set(salbum2); + + // Create page buttons + SDL_Rect rpage1d={60+(85*0),64,82,25}; + SDL_Rect rpage2d={60+(85*1),64,82,25}; + SDL_Rect rpage3d={60+(85*2),64,82,25}; + SDL_Rect rpage4d={60+(85*3),64,82,25}; + SDL_Rect rpage5d={60+(85*4),64,82,25}; + SDL_Rect rpage1sn={(85*0),328,82,25}; + SDL_Rect rpage1ss={(85*0),356,82,25}; + SDL_Rect rpage2sn={(85*1),328,82,25}; + SDL_Rect rpage2ss={(85*1),356,82,25}; + SDL_Rect rpage3sn={(85*2),328,82,25}; + SDL_Rect rpage3ss={(85*2),356,82,25}; + SDL_Rect rpage4sn={(85*3),328,82,25}; + SDL_Rect rpage4ss={(85*3),356,82,25}; + SDL_Rect rpage5sn={(85*4),328,82,25}; + SDL_Rect rpage5ss={(85*4),356,82,25}; + SDL_Surface *sparts=EDL_MaskSurface(pparts,mparts,0); + w_pages[0]=new ValueButton(rpage1d); + w_pages[0]->SetState(WS_NORMAL,sparts,&rpage1sn,sparts,&rpage1ss); + w_pages[0]->SetState(WS_HOVER,sparts,&rpage1sn,sparts,&rpage1ss); + w_pages[0]->SetState(WS_SELECT,sparts,&rpage1sn,sparts,&rpage1ss); + w_pages[0]->ChangeState(WS_NORMAL); + w_pages[1]=new ValueButton(rpage2d); + w_pages[1]->SetState(WS_NORMAL,sparts,&rpage2sn,sparts,&rpage2ss); + w_pages[1]->SetState(WS_HOVER,sparts,&rpage2sn,sparts,&rpage2ss); + w_pages[1]->SetState(WS_SELECT,sparts,&rpage2sn,sparts,&rpage2ss); + w_pages[1]->ChangeState(WS_NORMAL); + w_pages[2]=new ValueButton(rpage3d); + w_pages[2]->SetState(WS_NORMAL,sparts,&rpage3sn,sparts,&rpage3ss); + w_pages[2]->SetState(WS_HOVER,sparts,&rpage3sn,sparts,&rpage3ss); + w_pages[2]->SetState(WS_SELECT,sparts,&rpage3sn,sparts,&rpage3ss); + w_pages[2]->ChangeState(WS_NORMAL); + w_pages[3]=new ValueButton(rpage4d); + w_pages[3]->SetState(WS_NORMAL,sparts,&rpage4sn,sparts,&rpage4ss); + w_pages[3]->SetState(WS_HOVER,sparts,&rpage4sn,sparts,&rpage4ss); + w_pages[3]->SetState(WS_SELECT,sparts,&rpage4sn,sparts,&rpage4ss); + w_pages[3]->ChangeState(WS_NORMAL); + w_pages[4]=new ValueButton(rpage5d); + w_pages[4]->SetState(WS_NORMAL,sparts,&rpage5sn,sparts,&rpage5ss); + w_pages[4]->SetState(WS_HOVER,sparts,&rpage5sn,sparts,&rpage5ss); + w_pages[4]->SetState(WS_SELECT,sparts,&rpage5sn,sparts,&rpage5ss); + w_pages[4]->ChangeState(WS_NORMAL); + + // Create modebutton + SDL_Rect rmodedspd={540,260,100,56}; + SDL_Rect rmodebtnd={556,391,100,36}; + SDL_Rect rmodebtns={112,200,100,36}; + w_modedsp=new Widget(rmodedspd); + w_modebtn=new BitmapButton(rmodebtnd); + w_modebtn->SetState(WS_NORMAL,salbum2,&rmodebtnd); + w_modebtn->SetState(WS_HOVER,sparts,&rmodebtns); + w_modebtn->SetState(WS_SELECT,sparts,&rmodebtns); + w_modebtn->ChangeState(WS_NORMAL); + + // Create exit button + SDL_Rect rexitd={551,447,100,32}; + SDL_Rect rexits={112,120,100,32}; + w_exit=new BitmapButton(rexitd); + w_exit->SetState(WS_NORMAL,salbum2,&rexitd); + w_exit->SetState(WS_HOVER,sparts,&rexits); + w_exit->SetState(WS_SELECT,sparts,&rexits); + w_exit->ChangeState(WS_NORMAL); + + // Create sprites + SDL_Surface *pmarker=Engine->LoadImage("akiho.bet"); + SDL_Surface *mmarker=Engine->LoadImage("akiho_.bet"); + SDL_Surface *smarker=EDL_MaskSurface(pmarker,mmarker,0); + SDL_Rect rmarker={0,0,240/5,64}; + w_hover=new Sprite(rmarker); + w_hover->AddFrame(smarker,&rmarker,100); + rmarker.x+=rmarker.w; + w_hover->AddFrame(smarker,&rmarker,100); + rmarker.x+=rmarker.w; + w_hover->AddFrame(smarker,&rmarker,100); + rmarker.x+=rmarker.w; + w_hover->AddFrame(smarker,&rmarker,100); + rmarker.x+=rmarker.w; + w_hover->AddFrame(smarker,&rmarker,100); + w_hover->Move(rpage1d.x+20,rpage1d.y-rpage1d.h); + + // Create bgm widgets + SDL_Rect rbgmd={550,58,27,27}; + SDL_Rect rbgms={0,0,rbgmd.w,rbgmd.h}; + for(int i=0;i<6;i++){ + w_bgm[i]=new ValueButton(rbgmd); + w_bgm[i]->SetState(WS_NORMAL,salbum2,&rbgmd,sparts,&rbgms); + w_bgm[i]->SetState(WS_HOVER,sparts,&rbgms,sparts,&rbgms); + w_bgm[i]->SetState(WS_SELECT,sparts,&rbgms,sparts,&rbgms); + w_bgm[i]->ChangeState(WS_NORMAL); + AddWidget(w_bgm[i]); + rbgms.x+=(rbgmd.w+1); + rbgmd.y+=(rbgmd.h+5); + } + rbgmd.x+=44; + rbgmd.y=58; + rbgms.x=0; + rbgms.y+=28; + for(int i=6;i<11;i++){ + w_bgm[i]=new ValueButton(rbgmd); + w_bgm[i]->SetState(WS_NORMAL,salbum2,&rbgmd,sparts,&rbgms); + w_bgm[i]->SetState(WS_HOVER,sparts,&rbgms,sparts,&rbgms); + w_bgm[i]->SetState(WS_SELECT,sparts,&rbgms,sparts,&rbgms); + w_bgm[i]->ChangeState(WS_NORMAL); + AddWidget(w_bgm[i]); + rbgms.x+=(rbgmd.w+1); + rbgmd.y+=(rbgmd.h+5); + } + + + // Create item widgets + w_itembg=new Widget(); + w_itembg->Move(30,105); + AddWidget(w_itembg); + SDL_Rect ritemd={36,111,112,84}; + SDL_Rect ritems={0,116,112,100}; + for(int i=0;i<4;i++){ + ritemd.x=36; + for(int j=0;j<4;j++){ + w_items[(i*4)+j]=new Hotspot(ritemd); + w_items[(i*4)+j]->Blit(sparts,&ritems); + ritemd.x+=(ritemd.w+4); + AddWidget(w_items[(i*4)+j]); + } + ritemd.y+=(ritemd.h+4); + } + + // Assign widgets + AddWidget(w_pages[0]); + AddWidget(w_pages[1]); + AddWidget(w_pages[2]); + AddWidget(w_pages[3]); + AddWidget(w_pages[4]); + AddWidget(w_modedsp); + AddWidget(w_modebtn); + AddWidget(w_exit); + AddWidget(w_hover); + + // Free graphics + SDL_FreeSurface(salbum2); + SDL_FreeSurface(salbum1); + SDL_FreeSurface(palbum1); + SDL_FreeSurface(malbum1); + SDL_FreeSurface(sparts); + SDL_FreeSurface(pparts); + SDL_FreeSurface(mparts); + SDL_FreeSurface(smarker); + SDL_FreeSurface(pmarker); + SDL_FreeSurface(mmarker); + + // Load default page + SetMode(AM_CG); + SetPage(0); + } +} + +MCAlbum::~MCAlbum(){ + DestroyWidgets(); +} + +void MCAlbum::SetMode(ALBUM_MODE Mode){ + mode=Mode; + SDL_Rect rmodedsps={112,61,100,55}; + if(mode==AM_STORY){ + rmodedsps.x=0; + } + SDL_Surface *pparts=((Mayclub*)engine)->LoadImage("albumparts.bet"); + SDL_Surface *mparts=((Mayclub*)engine)->LoadImage("albumparts_.bet"); + if(pparts && mparts){ + SDL_Surface *sparts=EDL_MaskSurface(pparts,mparts,0); + w_modedsp->Blit(sparts,&rmodedsps); + SDL_FreeSurface(sparts); + SDL_FreeSurface(pparts); + SDL_FreeSurface(mparts); + } +} + +void MCAlbum::SetPage(int Page){ + if(Page>=0){ + // Load background + char name[32]; + if(mode==AM_CG){ + page=EDL_MIN(Page,4); + sprintf(name,"P%d.bet",page+1); + SDL_Surface *sbg=((Mayclub*)engine)->LoadImage(name); + if(sbg){ + w_itembg->Set(sbg); + SDL_FreeSurface(sbg); + } + + // Configure paginators + for(int i=0;i<5;i++){ + w_pages[i]->SetValue(false); + w_pages[i]->SetVisible(true); + w_pages[i]->SetHittable(true); + } + w_pages[page]->SetValue(true); + + // Configure hotspots + for(int i=5;i<16;i++){ + w_items[i]->SetVisible(true); + } + for(int i=0;i<16;i++){ + bool bit=false; + uString name; + ((Mayclub*)engine)->MapCG((Page*16)+i,&bit,&name); + w_items[i]->SetAlpha(bit?0:255); + } + } + if(mode==AM_STORY){ + page=EDL_MIN(Page,1); + sprintf(name,"st_P%d.bet",page+1); + SDL_Surface *sbg=((Mayclub*)engine)->LoadImage(name); + if(sbg){ + w_itembg->Set(sbg); + SDL_FreeSurface(sbg); + } + + // Configure paginators + for(int i=0;i<2;i++){ + w_pages[i]->SetValue(false); + w_pages[i]->SetVisible(true); + w_pages[i]->SetHittable(true); + } + for(int i=2;i<5;i++){ + w_pages[i]->SetValue(false); + w_pages[i]->SetVisible(false); + w_pages[i]->SetHittable(false); + } + w_pages[page]->SetValue(true); + + // Configure hotspots + for(int i=0;i<16;i++){ + bool bit=false; + uString name; + ((Mayclub*)engine)->MapScene((Page*16)+i,&bit,&name); + w_items[i]->SetAlpha(bit?0:255); + } + if(Page==1){ + for(int i=5;i<16;i++){ + w_items[i]->SetVisible(false); + } + } + else{ + for(int i=5;i<16;i++){ + w_items[i]->SetVisible(true); + } + } + + } + } +} + +bool MCAlbum::FocusEnter(Widget *Object){ + if(Object==w_pages[0] || + Object==w_pages[1] || + Object==w_pages[2] || + Object==w_pages[3] || + Object==w_pages[4]){ + w_hover->Move(Object->GetX()+20, + Object->GetY()-Object->GetHeight()); + w_hover->SetVisible(true); + } + return false; +} + +bool MCAlbum::FocusLeave(Widget *Object){ + w_hover->SetVisible(false); + return false; +} + +bool MCAlbum::InputOk(Widget *Object){ + bool retval=false; + if(Object==w_exit){ + // Close dialog + engine->DestroyWidget(this); + engine->SetTransition(); + retval=true; + } + else if(Object==w_modebtn){ + // Change mode + if(mode==AM_CG){ + SetMode(AM_STORY); + } + else{ + SetMode(AM_CG); + } + SetPage(page); + retval=true; + } + else if(Object==w_pages[0] || + Object==w_pages[1] || + Object==w_pages[2] || + Object==w_pages[3] || + Object==w_pages[4]){ + // Change page + if(Object==w_pages[0]) SetPage(0); + if(Object==w_pages[1]) SetPage(1); + if(Object==w_pages[2]) SetPage(2); + if(Object==w_pages[3]) SetPage(3); + if(Object==w_pages[4]) SetPage(4); + w_hover->SetVisible(false); + retval=true; + } + else if(Object==w_items[0] || + Object==w_items[1] || + Object==w_items[2] || + Object==w_items[3] || + Object==w_items[4] || + Object==w_items[5] || + Object==w_items[6] || + Object==w_items[7] || + Object==w_items[8] || + Object==w_items[9] || + Object==w_items[10] || + Object==w_items[11] || + Object==w_items[12] || + Object==w_items[13] || + Object==w_items[14] || + Object==w_items[15]){ + // Open item + int index=-1; + if(Object==w_items[0]) index=(page*16)+0; + if(Object==w_items[1]) index=(page*16)+1; + if(Object==w_items[2]) index=(page*16)+2; + if(Object==w_items[3]) index=(page*16)+3; + if(Object==w_items[4]) index=(page*16)+4; + if(Object==w_items[5]) index=(page*16)+5; + if(Object==w_items[6]) index=(page*16)+6; + if(Object==w_items[7]) index=(page*16)+7; + if(Object==w_items[8]) index=(page*16)+7; + if(Object==w_items[9]) index=(page*16)+7; + if(Object==w_items[10]) index=(page*16)+10; + if(Object==w_items[11]) index=(page*16)+11; + if(Object==w_items[12]) index=(page*16)+12; + if(Object==w_items[13]) index=(page*16)+13; + if(Object==w_items[14]) index=(page*16)+14; + if(Object==w_items[15]) index=(page*16)+15; + bool bit; + uString name; + SDL_Surface *cg; + if(mode==AM_CG){ + if(((Mayclub*)engine)->MapCG(index,&bit,&name) && bit){ + if((cg=engine->LoadImage(name))){ + engine->AddWidget(new PopImage(engine,cg),VL_OVERLAY); + SDL_FreeSurface(cg); + } + } + } + if(mode==AM_STORY){ + if(((Mayclub*)engine)->MapScene(index,&bit,&name) && bit){ + ((Mayclub*)engine)->FillBackground(0x000000FF); + if(((Mayclub*)engine)->LoadWindyScript(name)){ + engine->ShowLayer(VL_DIALOG,false); + } + } + } + retval=true; + } + else if(Object==w_bgm[0] || + Object==w_bgm[1] || + Object==w_bgm[2] || + Object==w_bgm[3] || + Object==w_bgm[4] || + Object==w_bgm[5] || + Object==w_bgm[6] || + Object==w_bgm[7] || + Object==w_bgm[8] || + Object==w_bgm[9] || + Object==w_bgm[10]){ + // Play bgm track + int bgm=-1; + if(Object==w_bgm[0]) bgm=0; + if(Object==w_bgm[1]) bgm=1; + if(Object==w_bgm[2]) bgm=2; + if(Object==w_bgm[3]) bgm=3; + if(Object==w_bgm[4]) bgm=4; + if(Object==w_bgm[5]) bgm=5; + if(Object==w_bgm[6]) bgm=6; + if(Object==w_bgm[7]) bgm=7; + if(Object==w_bgm[8]) bgm=8; + if(Object==w_bgm[9]) bgm=9; + if(Object==w_bgm[10]) bgm=10; + if(bgm>=0 && bgm<11){ + for(int i=0;i<11;i++){ + w_bgm[i]->SetValue(false); + } + w_bgm[bgm]->SetValue(true); + char bgmname[32]; + sprintf(bgmname,"%d",bgm+1); + ((Mayclub*)engine)->PlayMusic(bgmname); + } + retval=true; + } + + return retval; +} + + + diff --git a/engines/vileVN/windy/mayclub/mcalbum.h b/engines/vileVN/windy/mayclub/mcalbum.h new file mode 100644 index 0000000000..f1cca88f2f --- /dev/null +++ b/engines/vileVN/windy/mayclub/mcalbum.h @@ -0,0 +1,42 @@ +#ifndef _MCALBUM_H_ +#define _MCALBUM_H_ + +#include "../../dialogs/dlgbase.h" + +class Mayclub; + +enum ALBUM_MODE { + AM_CG, + AM_STORY, + AM_INVALID +}; + +class MCAlbum : public DialogBase { + private: + // Dialog widgets + Sprite *w_hover; + Widget *w_modedsp; + BitmapButton *w_modebtn; + BitmapButton *w_exit; + ValueButton *w_bgm[11]; + ValueButton *w_pages[5]; + Hotspot *w_items[16]; + Widget *w_itembg; + ALBUM_MODE mode; + int page; + + // Override events + virtual bool FocusEnter(Widget *Object); + virtual bool FocusLeave(Widget *Object); + virtual bool InputOk(Widget *Object); + public: + MCAlbum(Mayclub *Engine); + ~MCAlbum(); + + + void SetMode(ALBUM_MODE Mode); + void SetPage(int Page); +}; + +#endif + diff --git a/engines/vileVN/windy/mayclub/mcback.cpp b/engines/vileVN/windy/mayclub/mcback.cpp new file mode 100644 index 0000000000..f08fa541c6 --- /dev/null +++ b/engines/vileVN/windy/mayclub/mcback.cpp @@ -0,0 +1,114 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "mcback.h" +#include "mayclub.h" + +MCBack::MCBack(Mayclub *Engine,Textview *Texter) : DialogBase(Engine,true){ + // Load main menu graphics + SDL_Surface *sctp=Engine->LoadImage("ctp.bet"); + SDL_Surface *mctp=Engine->LoadImage("ctp_.bet"); + if(sctp && mctp){ + // Set widget graphics + SDL_Surface *ctp=EDL_MaskSurface(sctp,mctp,0); + SDL_Rect wpos={0,0,ctp->w,ctp->h/2}; + Set(ctp,&wpos,&wpos); + + // Create buttons + SDL_Rect rbutton={0,0,38,16}; + SDL_Rect rdest={14,10,rbutton.w,rbutton.h}; + SDL_Rect rsource={0,(ctp->h/2)+1,rbutton.w,rbutton.h}; + w_back=new BitmapButton(rdest); + w_back->SetState(WS_NORMAL,ctp,&rsource); + rsource.y+=rbutton.h; + w_back->SetState(WS_HOVER,ctp,&rsource); + w_back->SetState(WS_SELECT,ctp,&rsource); + AddWidget(w_back); + rdest.x+=38; + rsource.x+=38; + rsource.y-=rbutton.h; + w_stop=new BitmapButton(rdest); + w_stop->SetState(WS_NORMAL,ctp,&rsource); + rsource.y+=rbutton.h; + w_stop->SetState(WS_HOVER,ctp,&rsource); + w_stop->SetState(WS_SELECT,ctp,&rsource); + AddWidget(w_stop); + rdest.x+=38; + rsource.x+=38; + rsource.y-=rbutton.h; + w_next=new BitmapButton(rdest); + w_next->SetState(WS_NORMAL,ctp,&rsource); + rsource.y+=rbutton.h; + w_next->SetState(WS_HOVER,ctp,&rsource); + w_next->SetState(WS_SELECT,ctp,&rsource); + AddWidget(w_next); + + // Move dialog in place + MoveDialog(480,340); + + + // Free graphics + SDL_FreeSurface(ctp); + SDL_FreeSurface(sctp); + SDL_FreeSurface(mctp); + } + + // Disable textview logging + current=0; + texter=Texter; + texter->EnableTextlog(false); +} + +MCBack::~MCBack(){ + current=0; + uString tmp=texter->GetTextlog(current); + texter->ClearText(); + texter->PrintText(tmp); + texter->CompleteText(); + texter->EnableTextlog(true); +} + +bool MCBack::InputOk(Widget *Object){ + bool retval=false; + if(Object==w_back){ + retval=true; + current++; + uString tmp=texter->GetTextlog(current); + if(tmp.length()){ + texter->ClearText(); + texter->PrintText(tmp); + texter->CompleteText(); + } + else{ + current--; + } + } + if(Object==w_next){ + retval=true; + if(current>0){ + current--; + uString tmp=texter->GetTextlog(current); + texter->ClearText(); + texter->PrintText(tmp); + texter->CompleteText(); + } + } + if(Object==w_stop){ + engine->DestroyWidget(this); + retval=true; + } + return retval; +} + diff --git a/engines/vileVN/windy/mayclub/mcback.h b/engines/vileVN/windy/mayclub/mcback.h new file mode 100644 index 0000000000..c2baeb41ff --- /dev/null +++ b/engines/vileVN/windy/mayclub/mcback.h @@ -0,0 +1,25 @@ +#ifndef _MCBACK_H_ +#define _MCBACK_H_ + +#include "../../dialogs/textview.h" + +class Mayclub; + +class MCBack : public DialogBase { + private: + // Dialog widgets + BitmapButton *w_back; + BitmapButton *w_stop; + BitmapButton *w_next; + Textview *texter; + int current; + + // Override events + virtual bool InputOk(Widget *Object); + public: + MCBack(Mayclub *Engine,Textview *Texter); + ~MCBack(); +}; + +#endif + diff --git a/engines/vileVN/windy/mayclub/mcload.cpp b/engines/vileVN/windy/mayclub/mcload.cpp new file mode 100644 index 0000000000..6d1fad1980 --- /dev/null +++ b/engines/vileVN/windy/mayclub/mcload.cpp @@ -0,0 +1,219 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "mcload.h" +#include "mayclub.h" + +MCLoad::MCLoad(Mayclub *Engine) : DialogBase(Engine,true){ + // Load main menu graphics + SDL_Surface *sback=Engine->LoadImage("load.bet"); + SDL_Surface *smarker=Engine->LoadImage("marker.bet"); + SDL_Surface *mmarker=Engine->LoadImage("marker_.bet"); + SDL_Surface *skeywait=Engine->LoadImage("keywait.bet"); + SDL_Surface *mkeywait=Engine->LoadImage("keywait_.bet"); + + if(sback && smarker && mmarker && skeywait && mkeywait){ + // Fade in background graphics + SDL_Rect rfull={0,0,sback->w,sback->h}; + Engine->AddAnimation(new Fade(rfull,sback,rfull,1000)); + Move(rfull); + Set(sback); + + // Create button backgrounds + SDL_Rect rpage1d={109+(85*0),84,82,25}; + SDL_Rect rpage2d={109+(85*1),84,82,25}; + SDL_Rect rpage3d={109+(85*2),84,82,25}; + SDL_Rect rpage4d={109+(85*3),84,82,25}; + SDL_Rect rpage5d={109+(85*4),84,82,25}; + SDL_Rect rexitd={263,444,116,36}; + w_pages[0]=new Hotspot(rpage1d); + w_pages[1]=new Hotspot(rpage2d); + w_pages[2]=new Hotspot(rpage3d); + w_pages[3]=new Hotspot(rpage4d); + w_pages[4]=new Hotspot(rpage5d); + w_exit=new Hotspot(rexitd); + + // Create sprites + SDL_Rect rmarker={10,10,28,28}; + w_page=new Sprite(rmarker); + SDL_Surface *marker=EDL_MaskSurface(smarker,mmarker,0); + EDL_SETRECT(rmarker,0,0,28,28); + w_page->AddFrame(marker,&rmarker,100); + rmarker.x+=28; + w_page->AddFrame(marker,&rmarker,100); + rmarker.x+=28; + w_page->AddFrame(marker,&rmarker,100); + rmarker.x+=28; + w_page->AddFrame(marker,&rmarker,100); + rmarker.x+=28; + w_page->AddFrame(marker,&rmarker,100); + SDL_Rect rkeywait={10,10,32,32}; + w_hover=new Sprite(rkeywait); + SDL_Surface *keywait=EDL_MaskSurface(skeywait,mkeywait,0); + EDL_SETRECT(rkeywait,0,0,32,32); + w_hover->AddFrame(keywait,&rkeywait,100); + rkeywait.x+=32; + w_hover->AddFrame(keywait,&rkeywait,100); + rkeywait.x+=32; + w_hover->AddFrame(keywait,&rkeywait,100); + rkeywait.x+=32; + w_hover->AddFrame(keywait,&rkeywait,100); + + // Set default sprite positions and visibility + w_hover->SetVisible(false); + w_hover->Move(rpage1d.x+20,rpage1d.y-rpage1d.h); + w_page->Move(rpage1d.x+20,rpage1d.y-rpage1d.h); + + // Assign widgets + AddWidget(w_pages[0]); + AddWidget(w_pages[1]); + AddWidget(w_pages[2]); + AddWidget(w_pages[3]); + AddWidget(w_pages[4]); + AddWidget(w_exit); + AddWidget(w_page); + AddWidget(w_hover); + + // Create saveslab widgets + for(int i=0;i<4;i++){ + SDL_Rect rdest={1,117+(80*i),317,78}; + w_slabs[i]=new SaveSlab(rdest); + AddWidget(w_slabs[i]); + } + for(int i=4;i<8;i++){ + SDL_Rect rdest={320,117+(80*(i-4)),317,78}; + w_slabs[i]=new SaveSlab(rdest); + AddWidget(w_slabs[i]); + } + + // Free graphics + SDL_FreeSurface(sback); + SDL_FreeSurface(marker); + SDL_FreeSurface(smarker); + SDL_FreeSurface(mmarker); + SDL_FreeSurface(keywait); + SDL_FreeSurface(skeywait); + SDL_FreeSurface(mkeywait); + + // Load default page + page=-1; + LoadPage(0); + } +} + +MCLoad::~MCLoad(){ + DestroyWidgets(); +} + +void MCLoad::LoadPage(int Page){ + if(Page!=page){ + page=Page; + for(int i=0;i<8;i++){ + w_slabs[i]->Free(); + Savegame save(engine->NativeID(),(page*8)+i); + if(save.Read()){ + SDL_Surface *screen=0; + if(save.LoadSurface("screen-thumb",&screen,96,72)){ + // Set thumbview + SDL_Rect dst={3,3,96,72}; + w_slabs[i]->SetThumb(screen,0,&dst); + SDL_FreeSurface(screen); + + // Set saveinfo + EDL_SETRECT(dst,110,8,200,66); + uString savedate="Unknown date"; + save.LoadString("savedate",&savedate); + w_slabs[i]->SetText(savedate,&dst); + } + } + } + } +} + +bool MCLoad::FocusEnter(Widget *Object){ + if(Object==w_pages[0] || + Object==w_pages[1] || + Object==w_pages[2] || + Object==w_pages[3] || + Object==w_pages[4]){ + w_hover->Move(Object->GetX()+20, + Object->GetY()-Object->GetHeight()); + w_hover->SetVisible(w_page->GetX()!=w_hover->GetX()); + } + else if(Object==w_exit){ + w_hover->Move(Object->GetX()+20, + Object->GetY()-Object->GetHeight()); + w_hover->SetVisible(true); + } + return false; +} + +bool MCLoad::FocusLeave(Widget *Object){ + w_hover->SetVisible(false); + return false; +} + +bool MCLoad::InputOk(Widget *Object){ + bool retval=false; + if(Object==w_exit){ + // Close dialog + engine->DestroyWidget(this); + engine->SetTransition(); + retval=true; + } + else if(Object==w_pages[0] || + Object==w_pages[1] || + Object==w_pages[2] || + Object==w_pages[3] || + Object==w_pages[4]){ + // Change page + if(Object==w_pages[0]) LoadPage(0); + if(Object==w_pages[1]) LoadPage(1); + if(Object==w_pages[2]) LoadPage(2); + if(Object==w_pages[3]) LoadPage(3); + if(Object==w_pages[4]) LoadPage(4); + w_page->Move(w_hover->GetX(),w_hover->GetY()); + w_hover->SetVisible(false); + retval=true; + } + else if(Object==w_slabs[0] || + Object==w_slabs[1] || + Object==w_slabs[2] || + Object==w_slabs[3] || + Object==w_slabs[4] || + Object==w_slabs[5] || + Object==w_slabs[6] || + Object==w_slabs[7]){ + // Save game + int index=-1; + if(Object==w_slabs[0]) index=(page*8)+0; + if(Object==w_slabs[1]) index=(page*8)+1; + if(Object==w_slabs[2]) index=(page*8)+2; + if(Object==w_slabs[3]) index=(page*8)+3; + if(Object==w_slabs[4]) index=(page*8)+4; + if(Object==w_slabs[5]) index=(page*8)+5; + if(Object==w_slabs[6]) index=(page*8)+6; + if(Object==w_slabs[7]) index=(page*8)+7; + if(((Mayclub*)engine)->EventLoad(index)){ + engine->DestroyWidget(this); + engine->SetTransition(); + } + retval=true; + } + return retval; +} + + + diff --git a/engines/vileVN/windy/mayclub/mcload.h b/engines/vileVN/windy/mayclub/mcload.h new file mode 100644 index 0000000000..8b714a74b0 --- /dev/null +++ b/engines/vileVN/windy/mayclub/mcload.h @@ -0,0 +1,29 @@ +#ifndef _MCLOAD_H_ +#define _MCLOAD_H_ + +#include "../../dialogs/dlgbase.h" + +class Mayclub; + +class MCLoad : public DialogBase { + private: + // Dialog widgets + Sprite *w_page; + Sprite *w_hover; + SaveSlab *w_slabs[8]; + Hotspot *w_pages[5]; + Hotspot *w_exit; + int page; + + // Override events + virtual bool FocusEnter(Widget *Object); + virtual bool FocusLeave(Widget *Object); + virtual bool InputOk(Widget *Object); + public: + MCLoad(Mayclub *Engine); + ~MCLoad(); + void LoadPage(int Page); +}; + +#endif + diff --git a/engines/vileVN/windy/mayclub/mcmain.cpp b/engines/vileVN/windy/mayclub/mcmain.cpp new file mode 100644 index 0000000000..623fe7a0cd --- /dev/null +++ b/engines/vileVN/windy/mayclub/mcmain.cpp @@ -0,0 +1,178 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "mcmain.h" +#include "mayclub.h" + +MCMain::MCMain(Mayclub *Engine) : DialogBase(Engine,true){ + // Load buttons + w_button_newgame=new BitmapButton(); + w_button_loadgame=new BitmapButton(); + w_button_album=new BitmapButton(); + w_button_exit=new BitmapButton(); + AddWidget(w_button_newgame); + AddWidget(w_button_loadgame); + AddWidget(w_button_album); + AddWidget(w_button_exit); + + // Load main menu graphics + int width=Engine->NativeWidth(); + int height=Engine->NativeHeight(); + SDL_Surface *stitle1=Engine->LoadImage("title1.bet"); + SDL_Surface *stitle2=Engine->LoadImage("title2.bet"); + SDL_Surface *stitle3=Engine->LoadImage("title3.bet"); + SDL_Surface *ptitle4=Engine->LoadImage("title4.bet"); + SDL_Surface *mtitle4=Engine->LoadImage("title4_.bet"); + SDL_Surface *ptitlep=Engine->LoadImage("titlep.bet"); + SDL_Surface *mtitlep=Engine->LoadImage("titlep_.bet"); + if(stitle1 && stitle2 && stitle3 && + ptitle4 && mtitle4 && + ptitlep && mtitlep){ + // Fade in background graphics + SDL_Rect rfull={0,0,stitle1->w,stitle1->h}; + Engine->AddAnimation(new Fade(rfull,stitle1,rfull,1000)); + Engine->AddAnimation(new Fade(rfull,stitle2,rfull,1000)); + + SDL_Rect rstart,rdest; + Slide *tmpslide; + + // Slide menu across the screen beneath the chick + EDL_SETRECT(rstart, + width, + 200, + stitle3->w, + stitle3->h); + EDL_SETRECT(rdest, + 0, + 200, + stitle3->w, + stitle3->h); + tmpslide=new Slide(); + tmpslide->Set(stitle3); + tmpslide->Animate(rstart,rdest,500); + Engine->AddAnimation(tmpslide); + EDL_BlendSurface(stitle3,0,stitle2,&rdest); + + + // Slide chick across the screen + EDL_SETRECT(rstart, + width, + height-ptitle4->h, + ptitle4->w, + ptitle4->h); + EDL_SETRECT(rdest, + width-ptitle4->w, + height-ptitle4->h, + ptitle4->w, + ptitle4->h); + tmpslide=new Slide(); + SDL_Surface *stitle4=EDL_MaskSurface(ptitle4,mtitle4,0); + if(stitle4){ + tmpslide->Set(stitle4); + tmpslide->Animate(rstart,rdest,500); + Engine->AddAnimation(tmpslide); + EDL_BlendSurface(stitle4,0,stitle2,&rdest); + } + + // Set completed graphics as background + Move(rfull); + Set(stitle2); + + // Create compatible button graphics + SDL_Rect rselsize={0,0,20,20}; + SDL_Rect rselsource={0,356,rselsize.w,rselsize.h}; + SDL_Rect rseldest={10,10,rselsize.w,rselsize.h}; + SDL_Surface *stitlep=EDL_MaskSurface(ptitlep,mtitlep,&rselsource); + if(stitlep){ + // Configure button graphics + SDL_Rect rbutton={0,0,117,59}; + SDL_Rect rdest={28,219,rbutton.w,rbutton.h}; + SDL_Rect rsrc={28,19,rbutton.w,rbutton.h}; + w_button_newgame->Move(rdest.x,rdest.y); + w_button_newgame->Resize(rbutton.w,rbutton.h); + w_button_newgame->SetState(WS_NORMAL,stitle3,&rsrc); + EDL_SETRECT(rseldest,rsrc.x+6,rsrc.y+14,rselsize.w,rselsize.h); + EDL_BlitSurface(stitlep,0,stitle3,&rseldest); + w_button_newgame->SetState(WS_HOVER,stitle3,&rsrc); + + EDL_SETRECT(rdest,rdest.x,rdest.y+rbutton.h,rdest.w,rdest.h); + EDL_SETRECT(rsrc,rsrc.x,rsrc.y+rbutton.h,rsrc.w,rsrc.h); + w_button_loadgame->Move(rdest.x,rdest.y); + w_button_loadgame->Resize(rbutton.w,rbutton.h); + w_button_loadgame->SetState(WS_NORMAL,stitle3,&rsrc); + EDL_SETRECT(rseldest,rsrc.x+6,rsrc.y+14,rselsize.w,rselsize.h); + EDL_BlitSurface(stitlep,0,stitle3,&rseldest); + w_button_loadgame->SetState(WS_HOVER,stitle3,&rsrc); + + EDL_SETRECT(rdest,rdest.x,rdest.y+rbutton.h,rdest.w,rdest.h); + EDL_SETRECT(rsrc,rsrc.x,rsrc.y+rbutton.h,rsrc.w,rsrc.h); + w_button_album->Move(rdest.x,rdest.y); + w_button_album->Resize(rbutton.w,rbutton.h); + w_button_album->SetState(WS_NORMAL,stitle3,&rsrc); + EDL_SETRECT(rseldest,rsrc.x+6,rsrc.y+14,rselsize.w,rselsize.h); + EDL_BlitSurface(stitlep,0,stitle3,&rseldest); + w_button_album->SetState(WS_HOVER,stitle3,&rsrc); + + EDL_SETRECT(rdest,rdest.x,rdest.y+rbutton.h,rdest.w,rdest.h); + EDL_SETRECT(rsrc,rsrc.x,rsrc.y+rbutton.h,rsrc.w,rsrc.h); + w_button_exit->Move(rdest.x,rdest.y); + w_button_exit->Resize(rbutton.w,rbutton.h); + w_button_exit->SetState(WS_NORMAL,stitle3,&rsrc); + EDL_SETRECT(rseldest,rsrc.x+6,rsrc.y+14,rselsize.w,rselsize.h); + EDL_BlitSurface(stitlep,0,stitle3,&rseldest); + w_button_exit->SetState(WS_HOVER,stitle3,&rsrc); + } + + // Free graphics + SDL_FreeSurface(stitle1); + SDL_FreeSurface(stitle2); + SDL_FreeSurface(stitle3); + SDL_FreeSurface(ptitle4); + SDL_FreeSurface(mtitle4); + SDL_FreeSurface(stitle4); + SDL_FreeSurface(ptitlep); + SDL_FreeSurface(mtitlep); + SDL_FreeSurface(stitlep); + } +} + +bool MCMain::InputOk(Widget *Object){ + bool retval=false; + if(Object==w_button_newgame){ + // Load a new game from the original scripts + Mayclub *mcengine=(Mayclub*)engine; + mcengine->FillBackground(0xFFFFFFFF); + mcengine->EventNew(); + SetVisible(false); + retval=true; + } + else if(Object==w_button_loadgame){ + // Load dialog on top of this one + engine->AddWidget(new MCLoad((Mayclub*)engine),VL_DIALOG); + retval=true; + } + else if(Object==w_button_album){ + // Load dialog on top of this one + engine->AddWidget(new MCAlbum((Mayclub*)engine),VL_DIALOG); + retval=true; + } + else if(Object==w_button_exit){ + // Send shutdown signal to SDL + engine->EventGameShutdown(); + retval=true; + } + return retval; +} + diff --git a/engines/vileVN/windy/mayclub/mcmain.h b/engines/vileVN/windy/mayclub/mcmain.h new file mode 100644 index 0000000000..eba696f372 --- /dev/null +++ b/engines/vileVN/windy/mayclub/mcmain.h @@ -0,0 +1,23 @@ +#ifndef _MCMAIN_H_ +#define _MCMAIN_H_ + +#include "../../dialogs/dlgbase.h" + +class Mayclub; + +class MCMain : public DialogBase { + private: + // Dialog widgets + BitmapButton *w_button_newgame; + BitmapButton *w_button_loadgame; + BitmapButton *w_button_album; + BitmapButton *w_button_exit; + + // Override events + virtual bool InputOk(Widget *Object); + public: + MCMain(Mayclub *Engine); +}; + +#endif + diff --git a/engines/vileVN/windy/mayclub/mcsave.cpp b/engines/vileVN/windy/mayclub/mcsave.cpp new file mode 100644 index 0000000000..858f4e87f1 --- /dev/null +++ b/engines/vileVN/windy/mayclub/mcsave.cpp @@ -0,0 +1,219 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "mcsave.h" +#include "mayclub.h" + +MCSave::MCSave(Mayclub *Engine) : DialogBase(Engine,true){ + // Save main menu graphics + SDL_Surface *sback=Engine->LoadImage("save.bet"); + SDL_Surface *smarker=Engine->LoadImage("marker.bet"); + SDL_Surface *mmarker=Engine->LoadImage("marker_.bet"); + SDL_Surface *skeywait=Engine->LoadImage("keywait.bet"); + SDL_Surface *mkeywait=Engine->LoadImage("keywait_.bet"); + + if(sback && smarker && mmarker && skeywait && mkeywait){ + // Fade in background graphics + SDL_Rect rfull={0,0,sback->w,sback->h}; + Engine->AddAnimation(new Fade(rfull,sback,rfull,1000)); + Move(rfull); + Set(sback); + + // Create button backgrounds + SDL_Rect rpage1d={109+(85*0),84,82,25}; + SDL_Rect rpage2d={109+(85*1),84,82,25}; + SDL_Rect rpage3d={109+(85*2),84,82,25}; + SDL_Rect rpage4d={109+(85*3),84,82,25}; + SDL_Rect rpage5d={109+(85*4),84,82,25}; + SDL_Rect rexitd={263,444,116,36}; + w_pages[0]=new Hotspot(rpage1d); + w_pages[1]=new Hotspot(rpage2d); + w_pages[2]=new Hotspot(rpage3d); + w_pages[3]=new Hotspot(rpage4d); + w_pages[4]=new Hotspot(rpage5d); + w_exit=new Hotspot(rexitd); + + // Create sprites + SDL_Rect rmarker={10,10,28,28}; + w_page=new Sprite(rmarker); + SDL_Surface *marker=EDL_MaskSurface(smarker,mmarker,0); + EDL_SETRECT(rmarker,0,0,28,28); + w_page->AddFrame(marker,&rmarker,100); + rmarker.x+=28; + w_page->AddFrame(marker,&rmarker,100); + rmarker.x+=28; + w_page->AddFrame(marker,&rmarker,100); + rmarker.x+=28; + w_page->AddFrame(marker,&rmarker,100); + rmarker.x+=28; + w_page->AddFrame(marker,&rmarker,100); + SDL_Rect rkeywait={10,10,32,32}; + w_hover=new Sprite(rkeywait); + SDL_Surface *keywait=EDL_MaskSurface(skeywait,mkeywait,0); + EDL_SETRECT(rkeywait,0,0,32,32); + w_hover->AddFrame(keywait,&rkeywait,100); + rkeywait.x+=32; + w_hover->AddFrame(keywait,&rkeywait,100); + rkeywait.x+=32; + w_hover->AddFrame(keywait,&rkeywait,100); + rkeywait.x+=32; + w_hover->AddFrame(keywait,&rkeywait,100); + + // Set default sprite positions and visibility + w_hover->SetVisible(false); + w_hover->Move(rpage1d.x+20,rpage1d.y-rpage1d.h); + w_page->Move(rpage1d.x+20,rpage1d.y-rpage1d.h); + + // Assign widgets + AddWidget(w_pages[0]); + AddWidget(w_pages[1]); + AddWidget(w_pages[2]); + AddWidget(w_pages[3]); + AddWidget(w_pages[4]); + AddWidget(w_exit); + AddWidget(w_page); + AddWidget(w_hover); + + // Create saveslab widgets + for(int i=0;i<4;i++){ + SDL_Rect rdest={0,117+(80*i),317,78}; + w_slabs[i]=new SaveSlab(rdest); + AddWidget(w_slabs[i]); + } + for(int i=4;i<8;i++){ + SDL_Rect rdest={320,117+(80*(i-4)),317,78}; + w_slabs[i]=new SaveSlab(rdest); + AddWidget(w_slabs[i]); + } + + + // Free graphics + SDL_FreeSurface(sback); + SDL_FreeSurface(marker); + SDL_FreeSurface(smarker); + SDL_FreeSurface(mmarker); + SDL_FreeSurface(keywait); + SDL_FreeSurface(skeywait); + SDL_FreeSurface(mkeywait); + + // Set defaults + page=-1; + LoadPage(0); + } +} + +MCSave::~MCSave(){ + DestroyWidgets(); +} + +void MCSave::LoadPage(int Page){ + if(Page!=page){ + page=Page; + for(int i=0;i<8;i++){ + w_slabs[i]->Free(); + Savegame save(engine->NativeID(),(page*8)+i); + if(save.Read()){ + SDL_Surface *screen=0; + if(save.LoadSurface("screen-thumb",&screen,96,72)){ + // Set thumbview + SDL_Rect dst={3,3,96,72}; + w_slabs[i]->SetThumb(screen,0,&dst); + SDL_FreeSurface(screen); + + // Set saveinfo + EDL_SETRECT(dst,110,8,200,66); + uString savedate="Unknown date"; + save.LoadString("savedate",&savedate); + w_slabs[i]->SetText(savedate,&dst); + } + } + } + } +} + +bool MCSave::FocusEnter(Widget *Object){ + if(Object==w_pages[0] || + Object==w_pages[1] || + Object==w_pages[2] || + Object==w_pages[3] || + Object==w_pages[4]){ + w_hover->Move(Object->GetX()+20, + Object->GetY()-Object->GetHeight()); + w_hover->SetVisible(w_page->GetX()!=w_hover->GetX()); + } + else if(Object==w_exit){ + w_hover->Move(Object->GetX()+20, + Object->GetY()-Object->GetHeight()); + w_hover->SetVisible(true); + } + return false; +} + +bool MCSave::FocusLeave(Widget *Object){ + w_hover->SetVisible(false); + return false; +} + +bool MCSave::InputOk(Widget *Object){ + bool retval=false; + if(Object==w_exit){ + // Close dialog + engine->DestroyWidget(this); + engine->SetTransition(); + retval=true; + } + else if(Object==w_pages[0] || + Object==w_pages[1] || + Object==w_pages[2] || + Object==w_pages[3] || + Object==w_pages[4]){ + // Change page + if(Object==w_pages[0]) LoadPage(0); + if(Object==w_pages[1]) LoadPage(1); + if(Object==w_pages[2]) LoadPage(2); + if(Object==w_pages[3]) LoadPage(3); + if(Object==w_pages[4]) LoadPage(4); + w_page->Move(w_hover->GetX(),w_hover->GetY()); + w_hover->SetVisible(false); + retval=true; + } + else if(Object==w_slabs[0] || + Object==w_slabs[1] || + Object==w_slabs[2] || + Object==w_slabs[3] || + Object==w_slabs[4] || + Object==w_slabs[5] || + Object==w_slabs[6] || + Object==w_slabs[7]){ + // Save game + int index=-1; + if(Object==w_slabs[0]) index=(page*8)+0; + if(Object==w_slabs[1]) index=(page*8)+1; + if(Object==w_slabs[2]) index=(page*8)+2; + if(Object==w_slabs[3]) index=(page*8)+3; + if(Object==w_slabs[4]) index=(page*8)+4; + if(Object==w_slabs[5]) index=(page*8)+5; + if(Object==w_slabs[6]) index=(page*8)+6; + if(Object==w_slabs[7]) index=(page*8)+7; + if(((Mayclub*)engine)->EventSave(index)){ + engine->DestroyWidget(this); + engine->SetTransition(); + } + retval=true; + } + + return retval; +} + diff --git a/engines/vileVN/windy/mayclub/mcsave.h b/engines/vileVN/windy/mayclub/mcsave.h new file mode 100644 index 0000000000..06b3a2b15a --- /dev/null +++ b/engines/vileVN/windy/mayclub/mcsave.h @@ -0,0 +1,29 @@ +#ifndef _MCSAVE_H_ +#define _MCSAVE_H_ + +#include "../../dialogs/dlgbase.h" + +class Mayclub; + +class MCSave : public DialogBase { + private: + // Dialog widgets + Sprite *w_page; + Sprite *w_hover; + SaveSlab *w_slabs[8]; + Hotspot *w_pages[5]; + Hotspot *w_exit; + int page; + + // Override events + virtual bool FocusEnter(Widget *Object); + virtual bool FocusLeave(Widget *Object); + virtual bool InputOk(Widget *Object); + public: + MCSave(Mayclub *Engine); + ~MCSave(); + void LoadPage(int Page); +}; + +#endif + diff --git a/engines/vileVN/windy/mayclub/mctv.cpp b/engines/vileVN/windy/mayclub/mctv.cpp new file mode 100644 index 0000000000..22e110ef06 --- /dev/null +++ b/engines/vileVN/windy/mayclub/mctv.cpp @@ -0,0 +1,255 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "mctv.h" +#include "mayclub.h" + +MCTextview::MCTextview(Mayclub *Engine) : Textview(Engine) { + // Map up buttons surface + SDL_Rect cln_button; + SDL_Rect src_btn_save_1; + SDL_Rect src_btn_save_2; + SDL_Rect src_btn_load_1; + SDL_Rect src_btn_load_2; + SDL_Rect src_btn_back_1; + SDL_Rect src_btn_back_2; + SDL_Rect src_btn_back_3; + SDL_Rect src_btn_skip_1; + SDL_Rect src_btn_skip_2; + SDL_Rect src_btn_skip_3; + + // Map up destination surface + SDL_Rect dst_btn_save; + SDL_Rect dst_btn_load; + SDL_Rect dst_btn_skip; + SDL_Rect dst_btn_back; + + // Map buttons + EDL_SETRECT(cln_button,0,0,44,24); + EDL_SETRECT(src_btn_save_1,0,2,cln_button.w,cln_button.h); + EDL_SETRECT(src_btn_save_2,cln_button.w,2,cln_button.w,cln_button.h); + EDL_SETRECT(src_btn_load_1,0,30,cln_button.w,cln_button.h); + EDL_SETRECT(src_btn_load_2,cln_button.w,30,cln_button.w,cln_button.h); + EDL_SETRECT(src_btn_skip_1,0,60,cln_button.w,cln_button.h); + EDL_SETRECT(src_btn_skip_2,cln_button.w,60,cln_button.w,cln_button.h); + EDL_SETRECT(src_btn_skip_3,cln_button.w*2,60,cln_button.w,cln_button.h); + EDL_SETRECT(src_btn_back_1,0,86,cln_button.w,cln_button.h); + EDL_SETRECT(src_btn_back_2,cln_button.w,86,cln_button.w,cln_button.h); + EDL_SETRECT(src_btn_back_3,cln_button.w*2,86,cln_button.w,cln_button.h); + + // Map screen + EDL_SETRECT(dst_btn_save,20,392,cln_button.w,cln_button.h); + EDL_SETRECT(dst_btn_load,20,422,cln_button.w,cln_button.h); + EDL_SETRECT(dst_btn_back,576,392,cln_button.w,cln_button.h); + EDL_SETRECT(dst_btn_skip,576,422,cln_button.w,cln_button.h); + + // Load textview graphics + sbuttons=0; + swindow=0; + SDL_Surface *pmain=Engine->LoadImage("window.bet"); + SDL_Surface *pmask=Engine->LoadImage("window_.bet"); + if(pmain && pmask){ + SDL_Surface *bmain=Engine->LoadImage("button.bet"); + SDL_Surface *bmask=Engine->LoadImage("button_.bet"); + if(bmain && bmask){ + // Mask images + sbuttons=EDL_MaskSurface(bmain,bmask,0); + swindow=EDL_MaskSurface(pmain,pmask,0); + if(sbuttons && swindow){ + // Prepare widget object + Move(0,0); + Resize(swindow->w,swindow->h); + + // Configure apperance + Set(swindow); + SetTextPosition(80,384,480,84); + SetFontColor(0xFF,0xFF,0xFF); + + // Configure widgets + w_save=new BitmapButton(); + w_save->Move(dst_btn_save); + w_save->SetState(WS_NORMAL,sbuttons,&src_btn_save_1); + w_save->SetState(WS_HOVER,sbuttons,&src_btn_save_2); + w_save->SetState(WS_SELECT,sbuttons,&src_btn_save_1); + SetSaveButton(w_save); + w_load=new BitmapButton(); + w_load->Move(dst_btn_load); + w_load->SetState(WS_NORMAL,sbuttons,&src_btn_load_1); + w_load->SetState(WS_HOVER,sbuttons,&src_btn_load_2); + w_load->SetState(WS_SELECT,sbuttons,&src_btn_load_1); + SetLoadButton(w_load); + w_back=new BitmapButton(); + w_back->Move(dst_btn_back); + w_back->SetState(WS_NORMAL,sbuttons,&src_btn_back_1); + w_back->SetState(WS_HOVER,sbuttons,&src_btn_back_2); + w_back->SetState(WS_SELECT,sbuttons,&src_btn_back_1); + SetLoadButton(w_back); + w_skip=new BitmapButton(); + w_skip->Move(dst_btn_skip); + w_skip->SetState(WS_NORMAL,sbuttons,&src_btn_skip_1); + w_skip->SetState(WS_HOVER,sbuttons,&src_btn_skip_2); + w_skip->SetState(WS_SELECT,sbuttons,&src_btn_skip_1); + SetLoadButton(w_skip); + } + + // Clean up graphics + SDL_FreeSurface(bmain); + SDL_FreeSurface(bmask); + } + else{ + LogError("Cannot find textview overlay: button.bet"); + } + + // Clean up window graphics + SDL_FreeSurface(pmain); + SDL_FreeSurface(pmask); + } + else{ + LogError("Cannot find textview image: window.bet"); + } +} + +MCTextview::~MCTextview(){ + if(swindow){ + SDL_FreeSurface(swindow); + } + if(sbuttons){ + SDL_FreeSurface(sbuttons); + } +} + +bool MCTextview::InputOk(Widget *Object){ + bool retval=false; + if(Object==w_load){ + engine->EventGameDialog(VD_LOAD); + retval=true; + } + else if(Object==w_save){ + engine->EventGameDialog(VD_SAVE); + retval=true; + } + else if(Object==w_back){ + engine->EventGameDialog(VD_LOG); + } + else if(Object==w_skip){ + ((Mayclub*)engine)->SetSkipmode(true); + retval=true; + } + return retval; +} + +bool MCTextview::GetTimeofday(Uint16 TOD,SDL_Rect *R){ + if(TOD==0x0000) EDL_SETRECT((*R),0,112,72,72); + else if(TOD==0x0001) EDL_SETRECT((*R),72,112,72,72); + else if(TOD==0x0002) EDL_SETRECT((*R),0,184,72,72); + else if(TOD==0x0003) EDL_SETRECT((*R),72,184,72,72); + else return false; + return true; +} + +bool MCTextview::GetDayofweek(Uint16 DOW,SDL_Rect *R){ + if(DOW==0x0001) EDL_SETRECT((*R),28*0,256,28,12); + else if(DOW==0x0002) EDL_SETRECT((*R),28*1,256,28,12); + else if(DOW==0x0003) EDL_SETRECT((*R),28*2,256,28,12); + else if(DOW==0x0004) EDL_SETRECT((*R),28*3,256,28,12); + else if(DOW==0x0005) EDL_SETRECT((*R),28*0,268,28,12); + else if(DOW==0x0006) EDL_SETRECT((*R),28*1,268,28,12); + else if(DOW==0x0000) EDL_SETRECT((*R),28*2,268,28,12); + else return false; + return true; +} + +bool MCTextview::GetDigit(Uint16 Number,SDL_Rect *R){ + if(Number==0x0000) EDL_SETRECT((*R),20*0,280,20,24); + else if(Number==0x0001) EDL_SETRECT((*R),20*1,280,20,24); + else if(Number==0x0002) EDL_SETRECT((*R),20*2,280,20,24); + else if(Number==0x0003) EDL_SETRECT((*R),20*3,280,20,24); + else if(Number==0x0004) EDL_SETRECT((*R),20*4,280,20,24); + else if(Number==0x0005) EDL_SETRECT((*R),20*0,304,20,24); + else if(Number==0x0006) EDL_SETRECT((*R),20*1,304,20,24); + else if(Number==0x0007) EDL_SETRECT((*R),20*2,304,20,24); + else if(Number==0x0008) EDL_SETRECT((*R),20*3,304,20,24); + else if(Number==0x0009) EDL_SETRECT((*R),20*4,304,20,24); + else return false; + return true; +} + +bool MCTextview::SetTime(Uint16 Month,Uint16 Day,Uint16 TOD,Uint16 DOW){ + bool retval=(TOD<4); + SDL_Rect dst_month={24,9,20,24}; + SDL_Rect dst_day_1={60,9,20,24}; + SDL_Rect dst_day_2={78,9,20,24}; + SDL_Rect dst_timeofday={4,55,72,72}; + SDL_Rect dst_dayofweek={64,38,28,12}; + if(retval){ + // Clear old graphics + Blit(swindow,&dst_month,&dst_month); + Blit(swindow,&dst_day_1,&dst_day_1); + Blit(swindow,&dst_day_2,&dst_day_2); + Blit(swindow,&dst_dayofweek,&dst_dayofweek); + + // Paint new graphics + SDL_Rect src; + if(GetDigit(Month,&src)){ + Blend(sbuttons,&src,&dst_month); + } + if(Day){ + if(GetDigit(Day/10,&src)){ + Blend(sbuttons,&src,&dst_day_1); + } + if(GetDigit(Day%10,&src)){ + Blend(sbuttons,&src,&dst_day_2); + } + } + if(GetDayofweek(DOW,&src)){ + Blend(sbuttons,&src,&dst_dayofweek); + } + if(GetTimeofday(TOD,&src)){ + Blend(sbuttons,&src,&dst_timeofday); + } + } + return retval; +} + +bool MCTextview::SetTickets(Uint16 Tickets){ + bool retval=(Tickets<=99); + if(retval){ + // Clear old graphics + SDL_Rect dst_ticket_1={8,158,20,30}; + SDL_Rect dst_ticket_2={25,158,20,30}; + Blit(swindow,&dst_ticket_1,&dst_ticket_1); + Blit(swindow,&dst_ticket_2,&dst_ticket_2); + + // Paint new graphics + SDL_Rect src1; + SDL_Rect src2; + if(Tickets){ + if(GetDigit(Tickets/10,&src1) && GetDigit(Tickets%10,&src2)){ + Blend(sbuttons,&src1,&dst_ticket_1); + Blend(sbuttons,&src2,&dst_ticket_2); + } + } + else{ + if(GetDigit(0,&src1) && GetDigit(Tickets,&src2)){ + Blend(sbuttons,&src1,&dst_ticket_1); + Blend(sbuttons,&src2,&dst_ticket_2); + } + } + + } + return retval; +} + + diff --git a/engines/vileVN/windy/mayclub/mctv.h b/engines/vileVN/windy/mayclub/mctv.h new file mode 100644 index 0000000000..9bf71f1bed --- /dev/null +++ b/engines/vileVN/windy/mayclub/mctv.h @@ -0,0 +1,37 @@ +#ifndef _MAYCLUBTV_H_ +#define _MAYCLUBTV_H_ + +#include "../../dialogs/textview.h" + +class Mayclub; + +class MCTextview : public Textview { + private: + // Widgets + BitmapButton *w_load; + BitmapButton *w_save; + BitmapButton *w_back; + BitmapButton *w_skip; + + // Cache graphics + SDL_Surface *sbuttons; + SDL_Surface *swindow; + + // Helpers for mapping the screen + bool GetTimeofday(Uint16 TOD,SDL_Rect *R); + bool GetDayofweek(Uint16 DOW,SDL_Rect *R); + bool GetDigit(Uint16 Number,SDL_Rect *R); + public: + MCTextview(Mayclub *Engine); + ~MCTextview(); + + // Specialized methods + bool SetTickets(Uint16 Tickets); + bool SetTime(Uint16 Month,Uint16 Day,Uint16 TOD,Uint16 DOW); + + // Event overrides + virtual bool InputOk(Widget *Object); +}; + +#endif + diff --git a/engines/vileVN/windy/mayclub/mcwhisper.cpp b/engines/vileVN/windy/mayclub/mcwhisper.cpp new file mode 100644 index 0000000000..2a82dc5e61 --- /dev/null +++ b/engines/vileVN/windy/mayclub/mcwhisper.cpp @@ -0,0 +1,311 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "mcwhisper.h" + +MCWhisper::MCWhisper(EngineVN *Engine) : Whisper(Engine){ + datbuffer=0; + datsize=0; + pakbuffer=0; + paksize=0; + pakindex=0; + s21buffer=0; + s21size=0; + s21index=0; +} + +void MCWhisper::ParseScript(){ + for(;pakindex'Z'){ + pakindex++; + } + + // Extract script name + uString name; + while((pakbuffer[pakindex]>='A' && pakbuffer[pakindex]<='Z') || + (pakbuffer[pakindex]>='0' && pakbuffer[pakindex]<='9')){ + name+=(char)pakbuffer[pakindex++]; + } + + // Open new s21 script + RWops *s21blob=scripts.GetResource(name); + if(s21blob){ + if(s21buffer){ + delete [] s21buffer; + } + s21blob->Seek(0,SEEK_END); + s21size=s21blob->Tell(); + s21blob->Seek(0,SEEK_SET); + s21buffer=new Uint8[s21size]; + s21index=0; + s21blob->Read(s21buffer,s21size); + delete s21blob; + break; + } + } + } +} + +bool MCWhisper::ParseVoice(Uint16 Start){ + // Find next voice reference in current s21 script + bool retval=false; + uString voice; + for(int i=s21index;i+4='0' && s21buffer[j]<='9'){ + voice="V"; + voice+=datname[0]; + voice+=(char)s21buffer[j++]; + voice+=(char)s21buffer[j++]; + voice+=(char)s21buffer[j++]; + s21index=j; + //LogTest("ADDING:%d:%s",Start,voice.c_str()); + break; + } + } + break; + } + } + + if(voice.length()){ + // Register voice + SetVoice(Start,voice); + retval=true; + } + else if(pakindex='A' && datbuffer[j]<='z'); + } + if(quote && letters){ + //LogTest("REQUESTING:%s:%d",name.c_str(),Start); + ParseVoice(Start); + } + } + break; + } + } + } +} + +/*! \brief Processes english legacy script byte-by-byte + * \param Index Current index of the windy script + * \param Name Name of current windyscript + */ +void MCWhisper::ProcessScript(Uint16 Index){ + // Scan for text items in legacy source + bool processastext=true; + for(int i=Index;i=20 && datbuffer[index]<=126) && + (datbuffer[index-1]<20 || datbuffer[index-1]>126)){ + if(datbuffer[index]==0x0F){ + index+=3; + } + if(datbuffer[index]==0x03){ + index+=2; + } + + if(processastext){ + // Extract strings + int start=index; + int end=start; + for(;endLoadScript(Name); + RWops *pakblob=scripts.GetResource(Name); + s21buffer=0; + s21size=0; + s21index=0; + + if(datblob && !pakblob){ + // flat input + if((pakblob=scripts.GetResource(Name+'a'))){ + // Open new s21 script + RWops *s21blob=scripts.GetResource(Name+'a'); + if(s21blob){ + if(s21buffer){ + delete [] s21buffer; + } + s21blob->Seek(0,SEEK_END); + s21size=s21blob->Tell(); + s21blob->Seek(0,SEEK_SET); + s21buffer=new Uint8[s21size]; + s21index=0; + s21blob->Read(s21buffer,s21size); + delete s21blob; + } + } + } + + if(datblob && pakblob){ + // Flush existing data + ClearVoices(); + + // Read blobs to ram + datname=Name; + datblob->Seek(0,SEEK_END); + datsize=datblob->Tell(); + datblob->Seek(0,SEEK_SET); + datbuffer=new Uint8[datsize]; + pakblob->Seek(0,SEEK_END); + paksize=pakblob->Tell(); + pakblob->Seek(0,SEEK_SET); + pakbuffer=new Uint8[paksize]; + pakindex=0; + + // Recursively syncronize data to new scripts + if(datblob->Read(datbuffer,datsize)>0 && + pakblob->Read(pakbuffer,paksize)>0){ + // Decode windy script and process it + bool toggle=true; + for(int i=0;iLoadImage("omabg.ggd"); + if(sback){ + // Fade in background graphics + SDL_Rect rfull={0,0,sback->w,sback->h}; + Engine->AddAnimation(new Fade(rfull,sback,rfull,1000)); + Move(rfull); + Set(sback); + + // Create exit button + SDL_Rect rexitd={263,444,116,36}; + w_exit=new TextButton(rexitd,"Exit"); + AddWidget(w_exit); + + // Create saveslab widgets + for(int i=0;i<4;i++){ + SDL_Rect rdest={0,117+(80*i),317,78}; + w_slabs[i]=new SaveSlab(rdest); + AddWidget(w_slabs[i]); + } + for(int i=4;i<8;i++){ + SDL_Rect rdest={320,117+(80*(i-4)),317,78}; + w_slabs[i]=new SaveSlab(rdest); + AddWidget(w_slabs[i]); + } + + // Configure slabs + SDL_Rect rthumb={3,3,96,72}; + SDL_Rect rtext={110,8,200,64}; + for(int i=0;i<8;i++){ + // Alphablend some dead simple backgrounds + w_slabs[i]->Fill(0,0,0,255); + w_slabs[i]->SetAlpha(172); + w_slabs[i]->SetAlpha(128,&rtext); + + // Load savegame data + Savegame save(engine->NativeID(),i); + if(save.Read()){ + SDL_Surface *screen=0; + if(save.LoadSurface("screen-thumb",&screen,96,72)){ + // Set thumbview + w_slabs[i]->SetThumb(screen,0,&rthumb); + SDL_FreeSurface(screen); + + // Set saveinfo + uString savedate="Unknown date"; + save.LoadString("savedate",&savedate); + w_slabs[i]->SetText(savedate,&rtext); + } + } + else{ + w_slabs[i]->SetText("Empty slot",&rtext); + } + } + + // Free graphics + SDL_FreeSurface(sback); + } +} + +NILoad::~NILoad(){ + DestroyWidgets(); +} + +bool NILoad::InputOk(Widget *Object){ + bool retval=false; + if(Object==w_exit){ + // Close dialog + engine->DestroyWidget(this); + engine->SetTransition(); + retval=true; + } + else if(Object==w_slabs[0] || + Object==w_slabs[1] || + Object==w_slabs[2] || + Object==w_slabs[3] || + Object==w_slabs[4] || + Object==w_slabs[5] || + Object==w_slabs[6] || + Object==w_slabs[7]){ + // Load game + int index=-1; + if(Object==w_slabs[0]) index=0; + if(Object==w_slabs[1]) index=1; + if(Object==w_slabs[2]) index=2; + if(Object==w_slabs[3]) index=3; + if(Object==w_slabs[4]) index=4; + if(Object==w_slabs[5]) index=5; + if(Object==w_slabs[6]) index=6; + if(Object==w_slabs[7]) index=7; + if(((Nocturnal*)engine)->EventLoad(index)){ + engine->DestroyWidget(this); + engine->SetTransition(); + } + retval=true; + } + + return retval; +} + diff --git a/engines/vileVN/windy/nocturnal/niload.h b/engines/vileVN/windy/nocturnal/niload.h new file mode 100644 index 0000000000..a170cbe1f8 --- /dev/null +++ b/engines/vileVN/windy/nocturnal/niload.h @@ -0,0 +1,22 @@ +#ifndef _NILOAD_H_ +#define _NILOAD_H_ + +#include "../../dialogs/dlgbase.h" + +class Nocturnal; + +class NILoad : public DialogBase { + private: + // Dialog widgets + SaveSlab *w_slabs[8]; + TextButton *w_exit; + + // Override events + virtual bool InputOk(Widget *Object); + public: + NILoad(Nocturnal *Engine); + ~NILoad(); +}; + +#endif + diff --git a/engines/vileVN/windy/nocturnal/niloc.cpp b/engines/vileVN/windy/nocturnal/niloc.cpp new file mode 100644 index 0000000000..9b927f3f5d --- /dev/null +++ b/engines/vileVN/windy/nocturnal/niloc.cpp @@ -0,0 +1,344 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "niloc.h" +#include "nocturnal.h" + +NILocation::NILocation(Nocturnal *Engine) : DialogBase(Engine,true){ + if(Engine){ + // Load current + Uint8 floor=Engine->GetValue(0x0127); + switch(floor){ + case 0: LoadOutDoors(); break; + case 1: LoadFirstFloor(); break; + case 2: LoadSecondFloor(); break; + } + } +} + +void NILocation::LoadOutDoors(){ + Nocturnal *niengine=(Nocturnal*)engine; + SDL_Surface *sbase=niengine->LoadImage("od_base.ggd"); + SDL_Surface *s1=niengine->LoadImage("od_01.ggd"); + SDL_Surface *s2=niengine->LoadImage("od_02.ggd"); + SDL_Surface *s3=niengine->LoadImage("od_03.ggd"); + SDL_Surface *s4=niengine->LoadImage("od_04.ggd"); + SDL_Surface *s5=niengine->LoadImage("od_05.ggd"); + SDL_Surface *s6=niengine->LoadImage("od_06.ggd"); + if(sbase && s1 && s2 && s3 && s4 && s5 && s6){ + // Set centering offset + int offx=20; + int offy=0; + + // Get source rects + SDL_Rect r1s={0,0,s1->w-7,s1->h-6}; + SDL_Rect r2s={0,0,s2->w-7,s2->h-2}; + SDL_Rect r3s={0,0,s3->w-9,s3->h-6}; + SDL_Rect r4s={0,0,s4->w-7,s4->h-1}; + SDL_Rect r5s={0,0,s5->w-6,s5->h-2}; + SDL_Rect r6s={0,0,s6->w-7,s6->h-4}; + + // Get destination rects + SDL_Rect r1d={offx+235,offy+221,r1s.w,r1s.h}; + SDL_Rect r2d={offx+352,offy+190,r2s.w,r2s.h}; + SDL_Rect r3d={offx+410,offy+97,r3s.w,r3s.h}; + SDL_Rect r4d={offx+304,offy+64,r4s.w,r4s.h}; + SDL_Rect r5d={offx+174,offy+57,r5s.w,r5s.h}; + SDL_Rect r6d={offx+293,offy+108,r6s.w,r6s.h}; + + // Configure background + SDL_Surface *sbg=EDL_CreateSurface(640,384); + boxRGBA(sbg,0,0,640,384,0,0,0,0xFF); + SDL_Rect rbg={offx+56,offy+24,sbase->w,sbase->h}; + EDL_BlitSurface(sbase,0,sbg,&rbg); + Move(0,0); + Resize(640,384); + Blit(sbg); + SDL_FreeSurface(sbg); + + // Clear old widgets and load new ones + DestroyWidgets(); + AddWidget(loadbutton(1,sbase,s5,&r5s,&r5d)); + AddWidget(loadbutton(2,sbase,s6,&r6s,&r6d)); + AddWidget(loadbutton(3,sbase,s4,&r4s,&r4d)); + AddWidget(loadbutton(4,sbase,s3,&r3s,&r3d)); + AddWidget(loadbutton(5,sbase,s2,&r2s,&r2d)); + AddWidget(loadbutton(0,sbase,s1,&r1s,&r1d)); + + SDL_FreeSurface(s1); + SDL_FreeSurface(s2); + SDL_FreeSurface(s3); + SDL_FreeSurface(s4); + SDL_FreeSurface(s5); + SDL_FreeSurface(s6); + SDL_FreeSurface(sbase); + } + else{ + LogError("Failed to load location surfaces"); + } +} + +void NILocation::LoadSecondFloor(){ + Nocturnal *niengine=(Nocturnal*)engine; + SDL_Surface *sbase=niengine->LoadImage("2f_base.ggd"); + SDL_Surface *s1=niengine->LoadImage("2f_01.ggd"); + SDL_Surface *s2=niengine->LoadImage("2f_02.ggd"); + SDL_Surface *s3=niengine->LoadImage("2f_03.ggd"); + SDL_Surface *s4=niengine->LoadImage("2f_04.ggd"); + SDL_Surface *s5=niengine->LoadImage("2f_05.ggd"); + SDL_Surface *s6=niengine->LoadImage("2f_06.ggd"); + SDL_Surface *s7=niengine->LoadImage("2f_07.ggd"); + SDL_Surface *s8=niengine->LoadImage("2f_08.ggd"); + SDL_Surface *s9=niengine->LoadImage("2f_09.ggd"); + SDL_Surface *s10=niengine->LoadImage("2f_10.ggd"); + SDL_Surface *s11=niengine->LoadImage("2f_11.ggd"); + if(sbase && s1 && s2 && s3 && s4 && s5 && + s6 && s7 && s8 && s9 && s10 && s11){ + // Set centering offset + int offx=20; + int offy=0; + + // Get source rects + SDL_Rect r1s={0,0,s1->w-7,s1->h-4}; + SDL_Rect r2s={0,0,s2->w-4,s2->h-2}; + SDL_Rect r3s={0,0,s3->w-5,s3->h-1}; + SDL_Rect r4s={0,0,s4->w-4,s4->h-0}; + SDL_Rect r5s={0,0,s5->w-6,s5->h-5}; + SDL_Rect r6s={0,0,s6->w-3,s6->h-6}; + SDL_Rect r7s={0,0,s7->w-4,s7->h-6}; + SDL_Rect r8s={0,0,s8->w-8,s8->h-2}; + SDL_Rect r9s={0,0,s9->w-2,s9->h-7}; + SDL_Rect r10s={0,0,s10->w-0,s10->h-2}; + SDL_Rect r11s={0,0,s11->w-2,s11->h-3}; + + // Get destination rects + SDL_Rect r1d={offx+58,offy+152,r1s.w,r1s.h}; + SDL_Rect r2d={offx+100,offy+105,r2s.w,r2s.h}; + SDL_Rect r3d={offx+136,offy+64,r3s.w,r3s.h}; + SDL_Rect r4d={offx+169,offy+27,r4s.w,r4s.h}; + SDL_Rect r5d={offx+261,offy+52,r5s.w,r5s.h}; + SDL_Rect r6d={offx+199,offy+190,r6s.w,r6s.h}; + SDL_Rect r7d={offx+248,offy+82,r7s.w,r7s.h}; + SDL_Rect r8d={offx+425,offy+101,r8s.w,r8s.h}; + SDL_Rect r9d={offx+346,offy+251,r9s.w,r9s.h}; + SDL_Rect r10d={offx+375,offy+196,r10s.w,r10s.h}; + SDL_Rect r11d={offx+401,offy+145,r11s.w,r11s.h}; + + // Configure background + SDL_Surface *sbg=EDL_CreateSurface(640,384); + boxRGBA(sbg,0,0,640,384,0,0,0,0xFF); + SDL_Rect rbg={offx+56,offy+24,sbase->w,sbase->h}; + EDL_BlitSurface(sbase,0,sbg,&rbg); + Move(0,0); + Resize(640,384); + Blit(sbg); + SDL_FreeSurface(sbg); + + // Clear old widgets and load new ones + DestroyWidgets(); + AddWidget(loadbutton(0,sbase,s1,&r1s,&r1d)); // Redhead + AddWidget(loadbutton(1,sbase,s2,&r2s,&r2d)); // French doll + AddWidget(loadbutton(2,sbase,s3,&r3s,&r3d)); // Guest room + AddWidget(loadbutton(3,sbase,s4,&r4s,&r4d)); // Dude's room + AddWidget(loadbutton(4,sbase,s9,&r9s,&r9d)); // Home base + AddWidget(loadbutton(5,sbase,s10,&r10s,&r10d)); // Yukina + AddWidget(loadbutton(6,sbase,s11,&r11s,&r11d)); // Guest room + AddWidget(loadbutton(7,sbase,s8,&r8s,&r8d)); // Locked room + AddWidget(loadbutton(8,sbase,s6,&r6s,&r6d)); // Stairs + AddWidget(loadbutton(9,sbase,s7,&r7s,&r7d)); // Library + AddWidget(loadbutton(10,sbase,s5,&r5s,&r5d)); // Attic + SDL_FreeSurface(s1); + SDL_FreeSurface(s2); + SDL_FreeSurface(s3); + SDL_FreeSurface(s4); + SDL_FreeSurface(s5); + SDL_FreeSurface(s6); + SDL_FreeSurface(s7); + SDL_FreeSurface(s8); + SDL_FreeSurface(s9); + SDL_FreeSurface(s10); + SDL_FreeSurface(s11); + SDL_FreeSurface(sbase); + } + else{ + LogError("Failed to load location surfaces"); + } +} + +void NILocation::LoadFirstFloor(){ + Nocturnal *niengine=(Nocturnal*)engine; + SDL_Surface *sbase=niengine->LoadImage("1f_base.ggd"); + SDL_Surface *s1=niengine->LoadImage("1f_01.ggd"); + SDL_Surface *s2=niengine->LoadImage("1f_02.ggd"); + SDL_Surface *s3=niengine->LoadImage("1f_03.ggd"); + SDL_Surface *s4=niengine->LoadImage("1f_04.ggd"); + SDL_Surface *s5=niengine->LoadImage("1f_05.ggd"); + SDL_Surface *s6=niengine->LoadImage("1f_06.ggd"); + SDL_Surface *s7=niengine->LoadImage("1f_07.ggd"); + SDL_Surface *s8=niengine->LoadImage("1f_08.ggd"); + SDL_Surface *s9=niengine->LoadImage("1f_09.ggd"); + SDL_Surface *s10=niengine->LoadImage("1f_10.ggd"); + SDL_Surface *s11=niengine->LoadImage("1f_11.ggd"); + if(sbase && s1 && s2 && s3 && s4 && s5 && + s6 && s7 && s8 && s9 && s10 && s11){ + // Set centering offset + int offx=20; + int offy=0; + + // Get source rects + SDL_Rect r1s={0,0,s1->w-5,s1->h-4}; + SDL_Rect r2s={0,0,s2->w-4,s2->h-6}; + SDL_Rect r3s={0,0,s3->w-4,s3->h-4}; + SDL_Rect r4s={0,0,s4->w-7,s4->h-5}; + SDL_Rect r5s={0,0,s5->w-4,s5->h}; + SDL_Rect r6s={0,0,s6->w-7,s6->h}; + SDL_Rect r7s={0,0,s7->w-4,s7->h-6}; + SDL_Rect r8s={0,0,s8->w-5,s8->h-5}; + SDL_Rect r9s={0,0,s9->w-6,s9->h-7}; + SDL_Rect r10s={0,0,s10->w-4,s10->h-5}; + SDL_Rect r11s={0,0,s11->w-2,s11->h-7}; + + // Get destination rects + SDL_Rect r1d={offx+188,offy+238,r1s.w,r1s.h}; + SDL_Rect r2d={offx+401,offy+96,r2s.w,r2s.h}; + SDL_Rect r3d={offx+350,offy+245,r3s.w,r3s.h}; + SDL_Rect r4d={offx+376,offy+191,r4s.w,r4s.h}; + SDL_Rect r5d={offx+187,offy+166,r5s.w,r5s.h}; + SDL_Rect r6d={offx+293,offy+215,r6s.w,r6s.h}; + SDL_Rect r7d={offx+248,offy+81,r7s.w,r7s.h}; + SDL_Rect r8d={offx+261,offy+50,r8s.w,r8s.h}; + SDL_Rect r9d={offx+69,offy+153,r9s.w,r9s.h}; + SDL_Rect r10d={offx+107,offy+106,r10s.w,r10s.h}; + SDL_Rect r11d={offx+143,offy+28,r11s.w,r11s.h}; + + // Configure background + SDL_Surface *sbg=EDL_CreateSurface(640,384); + boxRGBA(sbg,0,0,640,384,0,0,0,0xFF); + SDL_Rect rbg={offx+56,offy+24,sbase->w,sbase->h}; + EDL_BlitSurface(sbase,0,sbg,&rbg); + Move(0,0); + Resize(640,384); + Blit(sbg); + SDL_FreeSurface(sbg); + + // Clear old widgets and load new ones + DestroyWidgets(); + AddWidget(loadbutton(0,sbase,s9,&r9s,&r9d)); + AddWidget(loadbutton(1,sbase,s10,&r10s,&r10d)); + AddWidget(loadbutton(2,sbase,s11,&r11s,&r11d)); + AddWidget(loadbutton(3,sbase,s3,&r3s,&r3d)); + AddWidget(loadbutton(4,sbase,s4,&r4s,&r4d)); + AddWidget(loadbutton(5,sbase,s2,&r2s,&r2d)); // Bath + AddWidget(loadbutton(7,sbase,s7,&r7s,&r7d)); // Kitchen + AddWidget(loadbutton(9,sbase,s8,&r8s,&r8d)); // Basement + + // New stuff ... + // Location 6 used to be a secondary menu (Lobby/Upstairs/Outside) + // Location 8 used to be the "cancel" item that returns you + // Location 10 is actually an overflow + AddWidget(loadbutton(6,sbase,s5,&r5s,&r5d)); // Lobby + AddWidget(loadbutton(8,sbase,s6,&r6s,&r6d)); // Upstairs + AddWidget(loadbutton(10,sbase,s1,&r1s,&r1d)); // Outside + + SDL_FreeSurface(s1); + SDL_FreeSurface(s2); + SDL_FreeSurface(s3); + SDL_FreeSurface(s4); + SDL_FreeSurface(s5); + SDL_FreeSurface(s6); + SDL_FreeSurface(s7); + SDL_FreeSurface(s8); + SDL_FreeSurface(s9); + SDL_FreeSurface(s10); + SDL_FreeSurface(s11); + SDL_FreeSurface(sbase); + } + else{ + LogError("Failed to load location surfaces"); + } +} + +/*! \brief Load a button using the specified sources and coordinates + * \param Tag Indentifying number + * \param Base Base graphics + * \param Icon Overlay graphics + * \param Source Coordinates to copy from the overlay graphics + * \param Dest Coordinates for the onscreen widget + */ +BitmapButton *NILocation::loadbutton(int Tag, + SDL_Surface *Base,SDL_Surface *Icon,SDL_Rect *Source,SDL_Rect *Dest){ + BitmapButton *tmpptr=new BitmapButton(*Dest); + tmpptr->SetState(WS_HOVER,Icon,Source); + tmpptr->SetTag(Tag); + return tmpptr; +} + +bool NILocation::InputOk(Widget *Object){ + if(Object && Object->GetTag()>=0){ + // Get settings from engine + Nocturnal *niengine=(Nocturnal*)engine; + Uint16 floor=niengine->GetValue(0x0127); + Uint16 room=Object->GetTag(); + + // Autoselect location + bool autoselect=false; + int selection=0; + if(floor==1){ + if(room==6){ + // Go to lobby + selection=2; + autoselect=true; + } + else if(room==8){ + // Go upstairs + floor=2; + selection=0; + autoselect=true; + } + else if(room==10){ + // Go outside + floor=0; + selection=1; + autoselect=true; + } + } + + // Unset scripted cache to avoid looping certain scenes + niengine->SetValue(0x008E,0x00FE); + + // Register location + LogDebug("Location: %d@%d%s",room,floor,autoselect?" (auto)":""); + niengine->SetValue(0x0000,selection); + //niengine->SetValue(0x012D,niengine->GetValue(0x0126)); + //niengine->SetValue(0x012E,niengine->GetValue(0x0127)); + //niengine->SetValue(0x0127,floor); + niengine->SetValue(0x0126,room); + + // Flush graphics if we are changing scenes + if((niengine->GetValue(0x0126)!=niengine->GetValue(0x012D)) || + (niengine->GetValue(0x0127)!=niengine->GetValue(0x012E))){ + niengine->FillBackground(0x000000FF); + } + + // Jump to menu selection + niengine->EventSelect(selection); + if(autoselect){ + niengine->Jump(0x7744); + } + } + return true; +} + + diff --git a/engines/vileVN/windy/nocturnal/niloc.h b/engines/vileVN/windy/nocturnal/niloc.h new file mode 100644 index 0000000000..4f3aad43b2 --- /dev/null +++ b/engines/vileVN/windy/nocturnal/niloc.h @@ -0,0 +1,21 @@ +#ifndef _NILOC_H_ +#define _NILOC_H_ + +#include "../../dialogs/dlgbase.h" + +class Nocturnal; + +class NILocation : public DialogBase { + private: + BitmapButton *loadbutton(int Tag,SDL_Surface *Base, + SDL_Surface *Icon,SDL_Rect *Source,SDL_Rect *Dest); + virtual bool InputOk(Widget *Object); + public: + NILocation(Nocturnal *Engine); + void LoadFirstFloor(); + void LoadSecondFloor(); + void LoadOutDoors(); +}; + +#endif + diff --git a/engines/vileVN/windy/nocturnal/nimain.cpp b/engines/vileVN/windy/nocturnal/nimain.cpp new file mode 100644 index 0000000000..6a6fc5fcda --- /dev/null +++ b/engines/vileVN/windy/nocturnal/nimain.cpp @@ -0,0 +1,87 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "nimain.h" +#include "niremenisce.h" +#include "nocturnal.h" + +NIMain::NIMain(Nocturnal *Engine) : DialogBase(Engine,true){ + // Load main menu graphics + SDL_Surface *stitle1=Engine->LoadImage("brand1.ggd"); + SDL_Surface *stitle2=Engine->LoadImage("brand2.ggd"); + SDL_Surface *stitle3=Engine->LoadImage("title.ggd"); + SDL_Surface *stitle4=Engine->LoadImage("sel.ggd"); + if(stitle1 && stitle2 && stitle3 && stitle4){ + // Fade in background graphics + Move(0,0); + Resize(stitle3->w,stitle3->h); + Set(stitle3); + SDL_Rect rfull={0,0,stitle1->w,stitle1->h}; + Engine->AddAnimation(new Fade(rfull,stitle1,rfull,1000)); + Engine->AddAnimation(new Fade(rfull,stitle2,rfull,1000)); + Engine->AddAnimation(new Fade(rfull,stitle3,rfull,3000)); + + // Load selection dialog + SDL_Rect rmenu={40,40,stitle4->w,stitle4->h}; + SDL_Rect ritem={60,50,stitle4->w-40,20}; + w_button_newgame=new TextButton(ritem,"New Game"); + AddWidget(w_button_newgame); + ritem.y+=24; + w_button_loadgame=new TextButton(ritem,"Load Game"); + AddWidget(w_button_loadgame); + ritem.y+=24; + w_button_album=new TextButton(ritem,"Remenisce"); + AddWidget(w_button_album); + ritem.y+=24; + w_button_exit=new TextButton(ritem,"Exit"); + AddWidget(w_button_exit); + Blend(stitle4,0,&rmenu); + + // Free graphics + SDL_FreeSurface(stitle1); + SDL_FreeSurface(stitle2); + SDL_FreeSurface(stitle3); + SDL_FreeSurface(stitle4); + } +} + +bool NIMain::InputOk(Widget *Object){ + bool retval=false; + Nocturnal *niengine=(Nocturnal*)engine; + if(niengine && Object==w_button_newgame){ + // Start a new game from the original scripts + niengine->EventNew(); + niengine->FillBackground(0xFFFFFFFF); + SetVisible(false); + retval=true; + } + else if(niengine && Object==w_button_loadgame){ + // Show load dialog + niengine->EventGameDialog(VD_LOAD); + retval=true; + } + else if(niengine && Object==w_button_album){ + // Show album/remenisce feature + niengine->AddWidget(new NIRemenisce(niengine),VL_DIALOG); + retval=true; + } + else if(niengine && Object==w_button_exit){ + // Send shutdown signal to SDL + niengine->EventGameShutdown(); + retval=true; + } + return retval; +} + diff --git a/engines/vileVN/windy/nocturnal/nimain.h b/engines/vileVN/windy/nocturnal/nimain.h new file mode 100644 index 0000000000..10836802bf --- /dev/null +++ b/engines/vileVN/windy/nocturnal/nimain.h @@ -0,0 +1,23 @@ +#ifndef _NIMAIN_H_ +#define _NIMAIN_H_ + +#include "../../dialogs/dlgbase.h" + +class Nocturnal; + +class NIMain : public DialogBase { + private: + // Dialog widgets + TextButton *w_button_newgame; + TextButton *w_button_loadgame; + TextButton *w_button_album; + TextButton *w_button_exit; + + // Override events + virtual bool InputOk(Widget *Object); + public: + NIMain(Nocturnal *Engine); +}; + +#endif + diff --git a/engines/vileVN/windy/nocturnal/niremenisce.cpp b/engines/vileVN/windy/nocturnal/niremenisce.cpp new file mode 100644 index 0000000000..47267a4657 --- /dev/null +++ b/engines/vileVN/windy/nocturnal/niremenisce.cpp @@ -0,0 +1,383 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "niremenisce.h" +#include "nocturnal.h" + +NIRemenisce::NIRemenisce(Nocturnal *Engine) : DialogBase(Engine,true){ + // Load remenisce graphics + mode=AM_SELECT; + SDL_Surface *omabg=Engine->LoadImage("omabg.ggd"); + if(omabg){ + // Fade in background graphics + SDL_Rect rfull={0,0,omabg->w,omabg->h}; + Move(rfull); + Engine->AddAnimation(new Fade(rfull,omabg,rfull,1000)); + Set(omabg); + SDL_FreeSurface(omabg); + } + + // Create exit button + SDL_Rect rexitd={551,447,100,32}; + w_back=new TextButton(rexitd,"Back"); + AddWidget(w_back); + + // Create menu + SDL_Surface *sel=Engine->LoadImage("sel.ggd"); + if(sel){ + int itemheight=sel->h/4; + SDL_Rect rsel={60,40+itemheight,sel->w-40,itemheight}; + w_menu[0]=new TextButton(rsel,"CG Mode"); + rsel.y+=itemheight; + w_menu[1]=new TextButton(rsel,"Music Mode"); + rsel.y+=itemheight; + AddWidget(w_menu[0]); + AddWidget(w_menu[1]); + SDL_FreeSurface(sel); + } + + // Create bgm widgets + SDL_Surface *bgm1=Engine->LoadImage("bgm1.ggd"); + SDL_Surface *bgm2=Engine->LoadImage("bgm2.ggd"); + if(bgm1 && bgm2){ + SDL_Rect rbgm={32,50,160,30}; + for(int i=0;i<6;i++){ + w_bgm[i]=new ValueButton(rbgm); + w_bgm[i]->SetState(WS_NORMAL,bgm1,&rbgm,bgm2,&rbgm); + w_bgm[i]->SetState(WS_HOVER,bgm2,&rbgm,bgm2,&rbgm); + w_bgm[i]->SetState(WS_SELECT,bgm2,&rbgm,bgm2,&rbgm); + w_bgm[i]->ChangeState(WS_NORMAL); + w_bgm[i]->SetVisible(false); + AddWidget(w_bgm[i]); + rbgm.y+=(rbgm.h+20); + } + rbgm.x+=190; + rbgm.y=50; + for(int i=6;i<12;i++){ + w_bgm[i]=new ValueButton(rbgm); + w_bgm[i]->SetState(WS_NORMAL,bgm1,&rbgm,bgm2,&rbgm); + w_bgm[i]->SetState(WS_HOVER,bgm2,&rbgm,bgm2,&rbgm); + w_bgm[i]->SetState(WS_SELECT,bgm2,&rbgm,bgm2,&rbgm); + w_bgm[i]->ChangeState(WS_NORMAL); + w_bgm[i]->SetVisible(false); + AddWidget(w_bgm[i]); + rbgm.y+=(rbgm.h+20); + } + rbgm.x+=190; + rbgm.y=50; + for(int i=12;i<18;i++){ + w_bgm[i]=new ValueButton(rbgm); + w_bgm[i]->SetState(WS_NORMAL,bgm1,&rbgm,bgm2,&rbgm); + w_bgm[i]->SetState(WS_HOVER,bgm2,&rbgm,bgm2,&rbgm); + w_bgm[i]->SetState(WS_SELECT,bgm2,&rbgm,bgm2,&rbgm); + w_bgm[i]->ChangeState(WS_NORMAL); + w_bgm[i]->SetVisible(false); + AddWidget(w_bgm[i]); + rbgm.y+=(rbgm.h+20); + } + + SDL_FreeSurface(bgm1); + SDL_FreeSurface(bgm2); + } + + // Create item widgets + SDL_Surface *sitem1=Engine->LoadImage("grp1.ggd"); + SDL_Surface *sitem2=Engine->LoadImage("grp2.ggd"); + if(sitem1 && sitem2){ + SDL_Rect ritem={20,64,144,96}; + for(int i=0;i<3;i++){ + w_items[i]=new ValueButton(ritem); + w_items[i]->SetState(WS_NORMAL,sitem2,&ritem,sitem1,&ritem); + w_items[i]->SetState(WS_HOVER,sitem2,&ritem,sitem1,&ritem); + w_items[i]->SetState(WS_SELECT,sitem2,&ritem,sitem1,&ritem); + w_items[i]->ChangeState(WS_NORMAL); + w_items[i]->SetVisible(false); + AddWidget(w_items[i]); + ritem.y+=(ritem.h+15); + } + ritem.x+=152; + ritem.y=64; + for(int i=3;i<6;i++){ + w_items[i]=new ValueButton(ritem); + w_items[i]->SetState(WS_NORMAL,sitem2,&ritem,sitem1,&ritem); + w_items[i]->SetState(WS_HOVER,sitem2,&ritem,sitem1,&ritem); + w_items[i]->SetState(WS_SELECT,sitem2,&ritem,sitem1,&ritem); + w_items[i]->ChangeState(WS_NORMAL); + w_items[i]->SetVisible(false); + AddWidget(w_items[i]); + ritem.y+=(ritem.h+15); + } + ritem.x+=152; + ritem.y=64; + for(int i=6;i<9;i++){ + w_items[i]=new ValueButton(ritem); + w_items[i]->SetState(WS_NORMAL,sitem2,&ritem,sitem1,&ritem); + w_items[i]->SetState(WS_HOVER,sitem2,&ritem,sitem1,&ritem); + w_items[i]->SetState(WS_SELECT,sitem2,&ritem,sitem1,&ritem); + w_items[i]->ChangeState(WS_NORMAL); + w_items[i]->SetVisible(false); + AddWidget(w_items[i]); + ritem.y+=(ritem.h+15); + } + ritem.x+=152; + ritem.y=64; + for(int i=9;i<11;i++){ + w_items[i]=new ValueButton(ritem); + w_items[i]->SetState(WS_NORMAL,sitem2,&ritem,sitem1,&ritem); + w_items[i]->SetState(WS_HOVER,sitem2,&ritem,sitem1,&ritem); + w_items[i]->SetState(WS_SELECT,sitem2,&ritem,sitem1,&ritem); + w_items[i]->ChangeState(WS_NORMAL); + w_items[i]->SetVisible(false); + AddWidget(w_items[i]); + ritem.y+=(ritem.h+15); + } + + // Free graphics + SDL_FreeSurface(sitem1); + SDL_FreeSurface(sitem2); + } + + SetModeSelect(); +} + +NIRemenisce::~NIRemenisce(){ + DestroyWidgets(); +} + +void NIRemenisce::SetModeSelect(){ + // Load background + SDL_Surface *omabg=engine->LoadImage("omabg.ggd"); + SDL_Surface *sel=engine->LoadImage("sel.ggd"); + if(omabg && sel){ + Blit(omabg); + SDL_Rect dst={40,40,sel->w,sel->h}; + Blit(sel,0,&dst); + SDL_FreeSurface(omabg); + SDL_FreeSurface(sel); + } + + // Hide items + for(int i=0;i<11;i++){ + w_items[i]->SetVisible(false); + } + + // Hide bgm controls + for(int i=0;i<18;i++){ + w_bgm[i]->SetVisible(false); + } + + // Show menu + mode=AM_SELECT; + for(int i=0;i<2;i++){ + w_menu[i]->SetVisible(true); + } +} + +void NIRemenisce::SetModeMusic(){ + // Load background + SDL_Surface *bgm1=engine->LoadImage("bgm1.ggd"); + if(bgm1){ + Blit(bgm1); + SDL_FreeSurface(bgm1); + } + + // Hide menu + for(int i=0;i<2;i++){ + w_menu[i]->SetVisible(false); + } + + // Show bgm controls + mode=AM_MUSIC; + for(int i=0;i<18;i++){ + w_bgm[i]->SetVisible(true); + w_bgm[i]->SetValue(false); + } +} + +void NIRemenisce::SetModeCG(){ + // Load background + SDL_Surface *sitem1=engine->LoadImage("grp1.ggd"); + if(sitem1){ + Blit(sitem1); + SDL_FreeSurface(sitem1); + } + + // Hide menu + for(int i=0;i<2;i++){ + w_menu[i]->SetVisible(false); + } + + // Configure hotspots + Nocturnal *niengine=(Nocturnal*)engine; + mode=AM_CG; + for(int i=0;i<11;i++){ + bool bit=false; + bool result=false; + uString name; + int s=0,e=0; + if(i==4){ s=0; e=15; } + if(i==0){ s=15; e=31; } + if(i==6){ s=31; e=40; } + if(i==7){ s=40; e=47; } + if(i==9){ s=47; e=57; } + if(i==1){ s=57; e=71; } + if(i==3){ s=72; e=82; } + if(i==10){ s=82; e=91; } + if(i==2){ s=91; e=100; } + if(i==5){ s=100; e=107; } + if(i==8){ s=107; e=111; } + if(e>0){ + for(int j=s;jMapCG(j,&bit,&name)){ + result|=bit; + } + } + } + w_items[i]->SetValue(result); + w_items[i]->SetVisible(true); + } +} + +bool NIRemenisce::InputOk(Widget *Object){ + bool retval=false; + if(Object==w_back){ + if(mode==AM_SELECT){ + // Close dialog + engine->DestroyWidget(this); + engine->SetTransition(); + retval=true; + } + else{ + // Back to remenisce menu + SetModeSelect(); + } + } + else if(Object==w_menu[0]){ + // CG Mode + SetModeCG(); + } + else if(Object==w_menu[1]){ + // Music Mode + SetModeMusic(); + } + else if(Object==w_items[0] || + Object==w_items[1] || + Object==w_items[2] || + Object==w_items[3] || + Object==w_items[4] || + Object==w_items[5] || + Object==w_items[6] || + Object==w_items[7] || + Object==w_items[8] || + Object==w_items[9] || + Object==w_items[10]){ + // Open item + bool bit; + uString name; + SDL_Surface *cg; + if(mode==AM_CG){ + // Extract unlocked images using indexes + Nocturnal *niengine=(Nocturnal*)engine; + PopImage *popimage=new PopImage(engine); + int s=0,e=0; + if(Object==w_items[4]){ s=0; e=15; } + if(Object==w_items[0]){ s=15; e=31; } + if(Object==w_items[6]){ s=31; e=40; } + if(Object==w_items[7]){ s=40; e=47; } + if(Object==w_items[9]){ s=47; e=57; } + if(Object==w_items[1]){ s=57; e=71; } + if(Object==w_items[3]){ s=72; e=82; } + if(Object==w_items[10]){ s=82; e=91; } + if(Object==w_items[2]){ s=91; e=100; } + if(Object==w_items[5]){ s=100; e=107; } + if(Object==w_items[8]){ s=107; e=111; } + bool result=false; + if(e>0){ + for(int j=s;jMapCG(j,&bit,&name) && bit){ + name=niengine->GetImagename(name); + if((cg=niengine->LoadImage(name))){ + popimage->AddImage(cg); + SDL_FreeSurface(cg); + result=true; + } + } + } + } + + // Show the images + if(result){ + niengine->AddWidget(popimage,VL_OVERLAY); + } + else{ + delete popimage; + } + } + retval=true; + } + else if(Object==w_bgm[0] || + Object==w_bgm[1] || + Object==w_bgm[2] || + Object==w_bgm[3] || + Object==w_bgm[4] || + Object==w_bgm[5] || + Object==w_bgm[6] || + Object==w_bgm[7] || + Object==w_bgm[8] || + Object==w_bgm[9] || + Object==w_bgm[10] || + Object==w_bgm[11] || + Object==w_bgm[12] || + Object==w_bgm[13] || + Object==w_bgm[14] || + Object==w_bgm[15] || + Object==w_bgm[16] || + Object==w_bgm[17]){ + // Play bgm track + int bgm=-1; + if(Object==w_bgm[0]) bgm=0; + if(Object==w_bgm[1]) bgm=1; + if(Object==w_bgm[2]) bgm=2; + if(Object==w_bgm[3]) bgm=3; + if(Object==w_bgm[4]) bgm=4; + if(Object==w_bgm[5]) bgm=5; + if(Object==w_bgm[6]) bgm=6; + if(Object==w_bgm[7]) bgm=7; + if(Object==w_bgm[8]) bgm=8; + if(Object==w_bgm[9]) bgm=9; + if(Object==w_bgm[10]) bgm=10; + if(Object==w_bgm[11]) bgm=11; + if(Object==w_bgm[12]) bgm=12; + if(Object==w_bgm[13]) bgm=13; + if(Object==w_bgm[14]) bgm=14; + if(Object==w_bgm[15]) bgm=15; + if(Object==w_bgm[16]) bgm=16; + if(Object==w_bgm[17]) bgm=17; + if(bgm>=0 && bgm<18){ + for(int i=0;i<18;i++){ + w_bgm[i]->SetValue(false); + } + w_bgm[bgm]->SetValue(true); + char bgmname[32]; + sprintf(bgmname,"%d",bgm+1); + ((Nocturnal*)engine)->PlayMusic(bgmname); + } + retval=true; + } + + return retval; +} + + diff --git a/engines/vileVN/windy/nocturnal/niremenisce.h b/engines/vileVN/windy/nocturnal/niremenisce.h new file mode 100644 index 0000000000..06f491f336 --- /dev/null +++ b/engines/vileVN/windy/nocturnal/niremenisce.h @@ -0,0 +1,34 @@ +#ifndef _NIREMENISCE_H_ +#define _NIREMENISCE_H_ + +#include "../../dialogs/dlgbase.h" + +class Nocturnal; + +enum ALBUM_MODE { + AM_CG, + AM_MUSIC, + AM_SELECT +}; + +class NIRemenisce : public DialogBase { + private: + // Dialog widgets + TextButton *w_back; + TextButton *w_menu[2]; + ValueButton *w_bgm[18]; + ValueButton *w_items[11]; + ALBUM_MODE mode; + + // Override events + virtual bool InputOk(Widget *Object); + public: + NIRemenisce(Nocturnal *Engine); + ~NIRemenisce(); + void SetModeSelect(); + void SetModeCG(); + void SetModeMusic(); +}; + +#endif + diff --git a/engines/vileVN/windy/nocturnal/nisave.cpp b/engines/vileVN/windy/nocturnal/nisave.cpp new file mode 100644 index 0000000000..5a5c9da8eb --- /dev/null +++ b/engines/vileVN/windy/nocturnal/nisave.cpp @@ -0,0 +1,119 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "nisave.h" +#include "nocturnal.h" + +NISave::NISave(Nocturnal *Engine) : DialogBase(Engine,true){ + // Save main menu graphics + SDL_Surface *sback=Engine->LoadImage("omabg.ggd"); + if(sback){ + // Fade in background graphics + SDL_Rect rfull={0,0,sback->w,sback->h}; + Engine->AddAnimation(new Fade(rfull,sback,rfull,1000)); + Move(rfull); + Set(sback); + + // Create exit button + SDL_Rect rexitd={263,444,116,36}; + w_exit=new TextButton(rexitd,"Exit"); + AddWidget(w_exit); + + // Create saveslab widgets + for(int i=0;i<4;i++){ + SDL_Rect rdest={0,117+(80*i),317,78}; + w_slabs[i]=new SaveSlab(rdest); + AddWidget(w_slabs[i]); + } + for(int i=4;i<8;i++){ + SDL_Rect rdest={320,117+(80*(i-4)),317,78}; + w_slabs[i]=new SaveSlab(rdest); + AddWidget(w_slabs[i]); + } + + // Configure slabs + SDL_Rect rthumb={3,3,96,72}; + SDL_Rect rtext={110,8,200,64}; + for(int i=0;i<8;i++){ + // Alphablend some dead simple backgrounds + w_slabs[i]->Fill(0,0,0,255); + w_slabs[i]->SetAlpha(172); + w_slabs[i]->SetAlpha(128,&rtext); + + // Load savegame data + Savegame save(engine->NativeID(),i); + if(save.Read()){ + SDL_Surface *screen=0; + if(save.LoadSurface("screen-thumb",&screen,96,72)){ + // Set thumbview + w_slabs[i]->SetThumb(screen,0,&rthumb); + SDL_FreeSurface(screen); + + // Set saveinfo + uString savedate="Unknown date"; + save.LoadString("savedate",&savedate); + w_slabs[i]->SetText(savedate,&rtext); + } + } + else{ + w_slabs[i]->SetText("Empty slot",&rtext); + } + } + + // Free graphics + SDL_FreeSurface(sback); + } +} + +NISave::~NISave(){ + DestroyWidgets(); +} + +bool NISave::InputOk(Widget *Object){ + bool retval=false; + if(Object==w_exit){ + // Close dialog + engine->DestroyWidget(this); + engine->SetTransition(); + retval=true; + } + else if(Object==w_slabs[0] || + Object==w_slabs[1] || + Object==w_slabs[2] || + Object==w_slabs[3] || + Object==w_slabs[4] || + Object==w_slabs[5] || + Object==w_slabs[6] || + Object==w_slabs[7]){ + // Save game + int index=-1; + if(Object==w_slabs[0]) index=0; + if(Object==w_slabs[1]) index=1; + if(Object==w_slabs[2]) index=2; + if(Object==w_slabs[3]) index=3; + if(Object==w_slabs[4]) index=4; + if(Object==w_slabs[5]) index=5; + if(Object==w_slabs[6]) index=6; + if(Object==w_slabs[7]) index=7; + if(((Nocturnal*)engine)->EventSave(index)){ + engine->DestroyWidget(this); + engine->SetTransition(); + } + retval=true; + } + + return retval; +} + diff --git a/engines/vileVN/windy/nocturnal/nisave.h b/engines/vileVN/windy/nocturnal/nisave.h new file mode 100644 index 0000000000..5dc3b615d5 --- /dev/null +++ b/engines/vileVN/windy/nocturnal/nisave.h @@ -0,0 +1,22 @@ +#ifndef _NISAVE_H_ +#define _NISAVE_H_ + +#include "../../dialogs/dlgbase.h" + +class Nocturnal; + +class NISave : public DialogBase { + private: + // Dialog widgets + SaveSlab *w_slabs[8]; + TextButton *w_exit; + + // Override events + virtual bool InputOk(Widget *Object); + public: + NISave(Nocturnal *Engine); + ~NISave(); +}; + +#endif + diff --git a/engines/vileVN/windy/nocturnal/nocturnal.cpp b/engines/vileVN/windy/nocturnal/nocturnal.cpp new file mode 100644 index 0000000000..c4dfd84780 --- /dev/null +++ b/engines/vileVN/windy/nocturnal/nocturnal.cpp @@ -0,0 +1,622 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "nocturnal.h" + +Nocturnal::Nocturnal(uString Path) : EngineWindy(640,480) { + // Set defaults + background=0; + menu_main_cache=0; + menu_sub_cache=0; + menu_main_flag=false; + + // Add ViLE patches + AddImages(new ArchiveViLE(Path+"nirdecensor.pck")); + + // Load english patches + AddScripts(new ArchiveFiles(Path+"OPEN.S")); + AddScripts(new ArchiveFiles(Path+"9_42.S")); + AddScripts(new ArchiveFiles(Path+"B_07.S")); + AddScripts(new ArchiveFiles(Path+"B_08.S")); + AddScripts(new ArchiveFiles(Path+"B_17.S")); + + // Load english legacy resources + AddScripts(new ArchiveWindy(Path+"mug0.dat")); + AddOther(new ArchiveFiles(Path+"svs")); + AddOther(new ArchiveFiles(Path+"svx")); + AddSE(new ArchiveFiles(Path+"*.WAV")); + + // Load new japanese resources + AddImages(new ArchiveIkura(Path+"GRP")); + //AddSE(new ArchiveIkura(Path+"SE")); + AddVoices(new ArchiveIkura(Path+"v1")); + AddVoices(new ArchiveIkura(Path+"v2")); + AddBGM(new ArchiveIkura(Path+"BGW")); + + // Assert subroutines + LoadWindyRoutines("MUG_SUB.S"); + + // Create and assign voice syncronizer + //whisper=new NIWhisper(this); + //whisper->AddResource(new ArchiveIkura(Path+"SNR")); + + // Cache menu backgrounds + iselection=0; + sselection[0]=LoadImage("SEL.GGD"); + sselection[1]=LoadImage("SELLAST.GGD"); + sselection[2]=LoadImage("SEL0.GGD"); + + // Create and assign textview object + SDL_Surface *stv=LoadImage("WAKU_H.GGD"); + if(stv){ + w_tv=new Textview(this); + w_tv->SetTextPosition(15,10,610,80); + w_tv->MoveDialog(0,NativeHeight()-stv->h); + w_tv->Resize(stv->w,stv->h); + w_tv->Set(stv); + AddWidget(w_tv,VL_TEXTVIEW); + SDL_FreeSurface(stv); + } + else{ + LogError("Could not load textview: WAKU_H.GGD"); + } + + // Map cgresources + int i=0; + RegisterCG(i++,"007"); + RegisterCG(i++,"017a"); + RegisterCG(i++,"017ao"); + RegisterCG(i++,"017b"); + RegisterCG(i++,"017c"); + RegisterCG(i++,"018"); + RegisterCG(i++,"019"); + RegisterCG(i++,"020"); + RegisterCG(i++,"021"); + RegisterCG(i++,"022"); + RegisterCG(i++,"023"); + RegisterCG(i++,"024"); + RegisterCG(i++,"091"); + RegisterCG(i++,"103"); + RegisterCG(i++,"120"); + RegisterCG(i++,"026"); + RegisterCG(i++,"027"); + RegisterCG(i++,"028"); + RegisterCG(i++,"030a"); + RegisterCG(i++,"030b"); + RegisterCG(i++,"030c"); + RegisterCG(i++,"030d"); + RegisterCG(i++,"031"); + RegisterCG(i++,"032"); + RegisterCG(i++,"033"); + RegisterCG(i++,"034"); + RegisterCG(i++,"035"); + RegisterCG(i++,"036"); + RegisterCG(i++,"092"); + RegisterCG(i++,"102"); + RegisterCG(i++,"114"); + RegisterCG(i++,"038"); + RegisterCG(i++,"040"); + RegisterCG(i++,"041"); + RegisterCG(i++,"042"); + RegisterCG(i++,"093"); + RegisterCG(i++,"104"); + RegisterCG(i++,"105"); + RegisterCG(i++,"106"); + RegisterCG(i++,"116"); + RegisterCG(i++,"044"); + RegisterCG(i++,"045"); + RegisterCG(i++,"046"); + RegisterCG(i++,"047"); + RegisterCG(i++,"094a"); + RegisterCG(i++,"112"); + RegisterCG(i++,"113"); + RegisterCG(i++,"050"); + RegisterCG(i++,"051"); + RegisterCG(i++,"053"); + RegisterCG(i++,"054a"); + RegisterCG(i++,"054b"); + RegisterCG(i++,"055"); + RegisterCG(i++,"056"); + RegisterCG(i++,"057"); + RegisterCG(i++,"095"); + RegisterCG(i++,"119"); + RegisterCG(i++,"058d"); + RegisterCG(i++,"059"); + RegisterCG(i++,"060a"); + RegisterCG(i++,"060b"); + RegisterCG(i++,"060c"); + RegisterCG(i++,"061"); + RegisterCG(i++,"062"); + RegisterCG(i++,"063"); + RegisterCG(i++,"096a"); + RegisterCG(i++,"096b"); + RegisterCG(i++,"097"); + RegisterCG(i++,"107"); + RegisterCG(i++,"117"); + RegisterCG(i++,"118"); + RegisterCG(i++,"065"); + RegisterCG(i++,"066"); + RegisterCG(i++,"067a"); + RegisterCG(i++,"067b"); + RegisterCG(i++,"067c"); + RegisterCG(i++,"068"); + RegisterCG(i++,"069"); + RegisterCG(i++,"070"); + RegisterCG(i++,"071"); + RegisterCG(i++,"098"); + RegisterCG(i++,"115"); + RegisterCG(i++,"073"); + RegisterCG(i++,"074"); + RegisterCG(i++,"075"); + RegisterCG(i++,"076"); + RegisterCG(i++,"077"); + RegisterCG(i++,"078"); + RegisterCG(i++,"100"); + RegisterCG(i++,"121a"); + RegisterCG(i++,"121b"); + RegisterCG(i++,"079a"); + RegisterCG(i++,"079b"); + RegisterCG(i++,"079c"); + RegisterCG(i++,"079d"); + RegisterCG(i++,"080"); + RegisterCG(i++,"081"); + RegisterCG(i++,"082"); + RegisterCG(i++,"101a"); + RegisterCG(i++,"101b"); + RegisterCG(i++,"085"); + RegisterCG(i++,"086a"); + RegisterCG(i++,"086b"); + RegisterCG(i++,"086c"); + RegisterCG(i++,"086d"); + RegisterCG(i++,"087"); + RegisterCG(i++,"088"); + RegisterCG(i++,"108"); + RegisterCG(i++,"109"); + RegisterCG(i++,"110"); + RegisterCG(i++,"111"); + + // Load main menu + main=new NIMain(this); + AddWidget(main,VL_DIALOG); + EventGameDialog(VD_TITLE); +} + +Nocturnal::~Nocturnal(){ + // Delete selection graphics + if(sselection[0]){ + SDL_FreeSurface(sselection[0]); + } + if(sselection[1]){ + SDL_FreeSurface(sselection[1]); + } + if(sselection[2]){ + SDL_FreeSurface(sselection[2]); + } + + // Delete cached graphics + if(background){ + SDL_FreeSurface(background); + } +} + +uString Nocturnal::GetImagename(uString Imagename){ + uString tmp=EDL_Searchname(Imagename); + if(tmp=="ara") return "mu132.ggd"; + else if(tmp=="07n") return "mu007an.ggd"; + else if(tmp=="10n") return "mu010an.ggd"; + else if(tmp=="2a1") return "mu072a1.ggd"; + else if(tmp=="2a2") return "mu072a2.ggd"; + else if(tmp=="2b1") return "mu072b1.ggd"; + else if(tmp=="2b2") return "mu072b2.ggd"; + else if(tmp=="2c1") return "mu072c1.ggd"; + else if(tmp=="2c2") return "mu072c2.ggd"; + else if(tmp=="2d1") return "mu072d1.ggd"; + else if(tmp=="2d2") return "mu072d2.ggd"; + else if(tmp=="4bd") return "mu064bd.ggd"; + else if(tmp=="7a2") return "mu037a.ggd"; + else if(tmp=="7b2") return "mu037b.ggd"; + else if(tmp=="7c2") return "mu037c.ggd"; + else if(tmp=="7d2") return "mu037d.ggd"; + else if(tmp=="7e2") return "mu037e.ggd"; + else if(tmp=="101") return "mu129.ggd"; + else if(tmp=="6c2") return "mu016c2.ggd"; + else if(tmp=="6d2") return "mu016d2.ggd"; + else if(tmp=="005b") return "mu130.ggd"; + else if(tmp=="mu058d") return "mu058d.ggd"; + else if(tmp=="mu094a") return "mu094a.ggd"; + else if(tmp=="mu094b") return "mu113.ggd"; + else if(tmp.length()){ + // Append prefix + uString ret="mu"; + + // Pad indexed bitmaps + if(tmp[tmp.length()-1].to_code()>='a'){ + if(tmp[tmp.length()-1].to_code()<='z'){ + ret+="0"; + } + } + + // Build remainder + ret+=tmp; + ret+=".ggd"; + return ret; + } + else{ + return ""; + } +} + +const uString Nocturnal::NativeID(){ + return "Nocturnal"; +} + +const uString Nocturnal::NativeName(){ + return "Nocturnal Illusion Renewal"; +} + +bool Nocturnal::PlayMusic(uString Name){ + // Generate name + bool retval=false; + char buffer[32]={0}; + int number=atoi(Name.c_str()); + if(number>0 && number<12){ + sprintf(buffer,"MUMU%02d.WAV",number); + retval=EngineVN::QueueMusic(buffer); + } + else if(number>0){ + sprintf(buffer,"MUNEW%02d.WAV",number-11); + retval=EngineVN::QueueMusic(buffer); + } + return retval; +} + +void Nocturnal::EventSelect(int Selection){ + // Cache selection values + if(menu_main_flag){ + // Unset submenu choice when main selection changes + if(menu_main_cache!=Selection){ + menu_sub_cache=0; + } + menu_main_cache=Selection; + } + else{ + menu_sub_cache=Selection; + } + + // Pass selection down to engine + EngineWindy::EventSelect(Selection); +} + +bool Nocturnal::LoadGraphics(uString Resource,Uint16 Index,Uint16 Type){ + LogTest("LOAD:%04x:%04x:%s",Index,Type,Resource.c_str()); + uString resource=GetImagename(Resource); + SDL_Surface *surface=LoadImage(resource.c_str()); + if(surface){ + Uint8 r,g,b,a,c=0; + EDL_GetPixel(surface,1,1,&r,&g,&b,&a); + Uint8 tr,tg,tb,ta; + + // Some images are overlayed in the old version, but not in the + // remake, so verify colorkey in other corners + EDL_GetPixel(surface,1,surface->h-1,&tr,&tg,&tb,&ta); + c=(tr==r && tg==g && tb==b && ta==a)?c+1:c; + EDL_GetPixel(surface,surface->w-1,1,&tr,&tg,&tb,&ta); + c=(tr==r && tg==g && tb==b && ta==a)?c+1:c; + EDL_GetPixel(surface,surface->w-1,surface->h-1,&tr,&tg,&tb,&ta); + c=(tr==r && tg==g && tb==b && ta==a)?c+1:c; + bool transparent=(c>=2); + if(transparent){ + Uint32 key=(r<<24)|(g<<16)|(b<<8)|0xFF; + SDL_Surface *masked=EDL_ColorkeySurface(surface,key,0); + if(masked){ + SDL_FreeSurface(surface); + surface=masked; + } + } + + if(transparent){ + // Blit background and blend in transparent image + if(background){ + w_bg->Blit(background); + } + w_bg->Blend(surface); + SDL_FreeSurface(surface); + } + else{ + // Cache background and blit it to display + if(background){ + SDL_FreeSurface(background); + } + background=surface; + w_bg->Blit(surface); + } + } + else{ + // Report missing image unless its the usual suspects + uString res=EDL_Searchname(Resource); + if(res!="90z" && res!="bk0" && res!="win" && res!="ttl"){ + LogError("Failed to load surface: %s",Resource.c_str()); + } + } + return surface; +} + +void Nocturnal::FillGraphics(Uint16 Index){ + int w=NativeWidth(); + int h=NativeHeight(); + SDL_Surface *source=EDL_CreateSurface(w,h); + boxRGBA(source,0,0,w,h,0,0,0,0xFF); + if(background){ + SDL_FreeSurface(background); + } + background=source; + w_bg->Fill(0x000000FF); +} + +Widget *Nocturnal::LoadSelection(Stringlist Strings, + Uint16 R1,Uint16 R2,Uint16 A1,Uint16 A2){ + // Clear text and set location as background until something is loaded + NILocation *location=new NILocation(this); + w_tv->ClearText(); + return location; +} + +Widget *Nocturnal::LoadSelection(Stringlist Strings){ + // Graphics selected in EventTextMode + if(iselection<0 || iselection>=3 || !sselection[iselection]){ + iselection=0; + } + if(iselection>=0 && iselection<3 && sselection[iselection]){ + SDL_Surface *selbitmap=sselection[iselection]; + Selection *seldialog=new Selection(this); + seldialog->Move(40,40); + seldialog->Resize(selbitmap->w,selbitmap->h); + seldialog->SetAlignment(HA_CENTER,VA_CENTER); + seldialog->Set(selbitmap,0,0); + seldialog->SetText(&Strings); + if(menu_main_flag){ + seldialog->SetFocusItem(menu_main_cache); + } + else{ + seldialog->SetFocusItem(menu_sub_cache); + } + return seldialog; + } + else{ + return 0; + } +} + +void Nocturnal::EventGameDialog(VN_DIALOGS Dialog){ + if(Dialog==VD_TITLE){ + DestroyLayer(VL_CHOICES); + StopMusic(); + StopSound(); + main->SetVisible(true); + PlayMusic("02"); + } + else if(Dialog==VD_SAVE){ + StdSave *dlg=new StdSave(this); + SDL_Surface *sback=LoadImage("omabg.ggd"); + if(sback){ + dlg->Blit(sback); + SDL_FreeSurface(sback); + } + AddWidget(dlg,VL_DIALOG); + } + else if(Dialog==VD_LOAD){ + StdLoad *dlg=new StdLoad(this); + SDL_Surface *sback=LoadImage("omabg.ggd"); + if(sback){ + dlg->Blit(sback); + SDL_FreeSurface(sback); + } + AddWidget(dlg,VL_DIALOG); + } + else if(Dialog==VD_CREDITS){ + // Scroll staffroll + SDL_Surface *surface=LoadImage("STAFROLL.GGD"); + if(surface){ + Sequences->RollPaddedVertical(surface); + Sequences->LogoRandom(0,0,0); + SDL_FreeSurface(surface); + } + + // Fade in titlescreen + surface=LoadImage("TITLE.GGD"); + if(surface){ + SDL_Rect dst={0,0,NativeWidth(),NativeHeight()}; + AddAnimation(new Fade(dst,surface,dst,5000)); + SDL_FreeSurface(surface); + } + } + else{ + EngineVN::EventGameDialog(Dialog); + } +} + +bool Nocturnal::EventSave(int Index){ + bool retval=EngineWindy::EventSave(Index); + if(retval){ + Savegame *save=new Savegame(NativeID(),Index); + save->Read(); + if(background){ + save->SaveSurface("screen-background",background); + } + save->Write(); + } + return retval; +} + +bool Nocturnal::EventLoad(int Index){ + bool retval=EngineWindy::EventLoad(Index); + if(retval){ + // Force textview to normal textmode + int x,y,w,h; + x=15; + y=NativeHeight()-w_tv->GetHeight()+8; + w=610; + h=84; + w_tv->ClearText(); + w_tv->SetTextPosition(x,y,w,h); + + // Load mayclub specific data + Savegame *load=new Savegame(NativeID(),Index); + load->Read(); + SDL_Surface *tmps; + if(load->LoadSurface("screen-background",&tmps)){ + if(background){ + SDL_FreeSurface(background); + } + background=tmps; + } + delete load; + + // Make sure the mainscreen is hidden + main->SetVisible(false); + } + return retval; +} + +void Nocturnal::EventNew(){ + // Force textview to normal textmode + int x,y,w,h; + x=15; + y=NativeHeight()-w_tv->GetHeight()+8; + w=610; + h=84; + w_tv->ClearText(); + w_tv->SetTextPosition(x,y,w,h); + + // Preset default values + EngineWindy::EventNew(); + SetValue(0x0127,2); // Current floor + SetValue(0x0126,4); // Current room + SetValue(0x012D,2); // Previous floor + SetValue(0x012E,4); // Previous room + + // Load initialization code + LoadWindyScript("OPEN.S",0x23B1); + SetTransition(); +} + +void Nocturnal::EventBlit(Uint16 Opcode,Uint16 Index){ + if(Opcode==0x002F){ + if(background){ + w_bg->Blit(background); + } + } +} + +void Nocturnal::EventTextMode(Uint16 Mode,Uint16 X,Uint16 Y, + Uint16 Width,Uint16 Height,Uint16 Flag){ + // Check for valid textmodes + int x=0,y=0,w=0,h=0; + if(Mode==0x000C || Mode==0x000D){ + // Register menu type and prepare cached selection graphics + menu_main_flag=(Mode==0x000C); + if(Height>6){ + iselection=1; + } + else if(Width>9){ + iselection=2; + } + else{ + iselection=0; + } + LogDebug("Preparing %s menu: %dx%dx%dx%d (%d)", + menu_main_flag?"main":"sub", + X,Y,Width,Height,Flag); + } + else if(Mode==0x0002 || Mode==0x0003 || Mode==0x000B || Mode==0x000F){ + LogDebug("Preparing text: %dx%dx%dx%d (%d/%d)", + X,Y,Width,Height,Mode,Flag); + //if((X==0x0007 && Y==0x000A) || + // (X==0x000A && Y==0x000A)){ + if(Y==0x000A){ + // Quotes for nocturnal illusion + x=100; + y=100; + w=610; + h=84; + } + else{ + // Fade quotes to black + if(w_tv->GetTextPosition(&x,&y,&w,&h)){ + if(yGetHeight()}; + AddAnimation(new FadeBlack(dst,5000)); + } + } + + // Default to normal mode + x=15; + y=NativeHeight()-w_tv->GetHeight()+8; + w=610; + h=84; + } + } + else{ + LogError("Unknown textmode for nocturnal: %d(%d,%d)",Mode,X,Y); + } + + // Change textmode if applicable + if(x || y || w || h){ + w_tv->ClearText(); + w_tv->SetTextPosition(x,y,w,h); + } +} + + +bool Nocturnal::EventExternal(Uint16 Address){ + // Override slow looping routines + bool retval=false; + if(Address==0x4150){ + // Skip graphical effects and load location menu + LogDebug("Skipping legacy effect (0x4150)"); + Call(0x6B86); + retval=true; + } + + // We have no idea why the bgm opcode doesnt register, but + // this hack should do the trick considering that we are + // closing up the windy engine. + static int ltrack=255; + int ntrack=vars.GetUint16(0x0200); + if(ntrack==0xFF){ + ltrack=ntrack; + } + else if(ntrack!=ltrack){ + int number=ntrack; + if(ntrack==0) number=1; + else if(ntrack==1) number=2; + else if(ntrack==2) number=3; + else if(ntrack==4) number=4; + else if(ntrack==6) number=11; + else if(ntrack==7) number=5; + else if(ntrack==8) number=6; + else if(ntrack==9) number=7; + else if(ntrack==11) number=8; + else if(ntrack==13) number=9; + else if(ntrack==14) number=10; + PlayMusic(EDL_Format("%02d",number)); + ltrack=ntrack; + } + return retval; +} + + diff --git a/engines/vileVN/windy/nocturnal/nocturnal.h b/engines/vileVN/windy/nocturnal/nocturnal.h new file mode 100644 index 0000000000..1480a6f1fc --- /dev/null +++ b/engines/vileVN/windy/nocturnal/nocturnal.h @@ -0,0 +1,52 @@ +/*! \class Nocturnal + * \brief Uses the windy engine to stage a Nocturnal Illusion game + */ +#ifndef _NOCTURNAL_H_ +#define _NOCTURNAL_H_ + +#include "../windy.h" +#include "nimain.h" +#include "nisave.h" +#include "niload.h" +#include "niloc.h" + +class Nocturnal : public EngineWindy { + private: + int iselection; //!< Currently used selection graphic + bool menu_main_flag; //!< True if current menu is a root menu + int menu_main_cache; //!< Holds last used main menu choice + int menu_sub_cache; //!< Holds last used main menu choice + SDL_Surface *background; //!< Cached background + SDL_Surface *sselection[3]; //!< Cached selection backgrounds + NIMain *main; //!< Cached main menu + public: + Nocturnal(uString Path); + ~Nocturnal(); + + // Windy overrides + virtual bool EventExternal(Uint16 Address); + virtual void EventBlit(Uint16 Opcode,Uint16 Index); + virtual void EventTextMode(Uint16 Mode,Uint16 X,Uint16 Y, + Uint16 Width,Uint16 Height,Uint16 Flag); + + // General overrides + virtual void EventGameDialog(VN_DIALOGS Dialog); + virtual bool EventSave(int Index); + virtual bool EventLoad(int Index); + virtual void EventNew(); + virtual void EventSelect(int Selection); + virtual const uString NativeID(); + virtual const uString NativeName(); + virtual bool PlayMusic(uString Name); + virtual bool LoadGraphics(uString Name,Uint16 Index,Uint16 Type); + virtual void FillGraphics(Uint16 Index); + virtual Widget *LoadSelection(Stringlist Strings); + virtual Widget *LoadSelection(Stringlist Strings, + Uint16 R1,Uint16 R2,Uint16 A1,Uint16 A2); + + // Helpers + uString GetImagename(uString Imagename); +}; + +#endif + diff --git a/engines/vileVN/windy/whisper.cpp b/engines/vileVN/windy/whisper.cpp new file mode 100644 index 0000000000..5f43fe82f2 --- /dev/null +++ b/engines/vileVN/windy/whisper.cpp @@ -0,0 +1,95 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "whisper.h" + +Whisper::Whisper(EngineVN *Engine){ + engine=Engine; + head=0; +} + +Whisper::~Whisper(){ + ClearVoices(); +} + +/*! \brief Skews the voice queue by dropping a voice reference + */ +void Whisper::DropVoice(int Position){ + WhisperItem *tmpptr=head; + for(int i=0;tmpptr && inext; + } + while(tmpptr){ + if(tmpptr->next){ + tmpptr->name=tmpptr->next->name; + } + else{ + tmpptr->address=0xFFFF; + } + tmpptr=tmpptr->next; + } +} + +/* +void Whisper::PushVoice(int Position){ +} +*/ + +void Whisper::AddResource(ArchiveBase *Archive){ + scripts.AddResource(Archive); +} + +uString Whisper::GetVoice(Uint16 Address){ + WhisperItem *tmpptr=head; + while(tmpptr){ + if(tmpptr->address==Address){ + return tmpptr->name; + } + else{ + tmpptr=tmpptr->next; + } + } + return ""; +} + +void Whisper::SetVoice(Uint16 Address,uString Name){ + WhisperItem *newitem=new WhisperItem; + newitem->address=Address; + newitem->name=Name; + newitem->next=0; + + if(head){ + WhisperItem *tmpptr=head; + while(tmpptr->next){ + tmpptr=tmpptr->next; + } + tmpptr->next=newitem; + } + else{ + head=newitem; + } +} + +/*! \brief Removes all currently indexed voice resources + */ +void Whisper::ClearVoices(){ + while(head){ + WhisperItem *tmpptr=head->next; + delete head; + head=tmpptr; + } +} + + diff --git a/engines/vileVN/windy/whisper.h b/engines/vileVN/windy/whisper.h new file mode 100644 index 0000000000..cd53286a89 --- /dev/null +++ b/engines/vileVN/windy/whisper.h @@ -0,0 +1,42 @@ +/*! \class Whisper + * \brief Indexes voice resources for Windy games + */ +#ifndef _WHISPER_H_ +#define _WHISPER_H_ + +#include "../engine/evn.h" + +class Whisper { + private: + // Store voices + struct WhisperItem { + uString name; + Uint16 address; + WhisperItem *next; + } *head; + protected: + // Keep track of resources + Resources scripts; + EngineVN *engine; + + // Adjusts queue + void DropVoice(int Position); + void PushVoice(int Position); + public: + Whisper(EngineVN *Engine); + virtual ~Whisper(); + + // Syncronize with new scripts + virtual void Synchronize(uString Name,Stringlist List)=0; + + // Add external resources + void AddResource(ArchiveBase *Archive); + + // Manage indexed voice resources + uString GetVoice(Uint16 Address); + void SetVoice(Uint16 Address,uString Name); + void ClearVoices(); +}; + +#endif + diff --git a/engines/vileVN/windy/windy.cpp b/engines/vileVN/windy/windy.cpp new file mode 100644 index 0000000000..e16d989f85 --- /dev/null +++ b/engines/vileVN/windy/windy.cpp @@ -0,0 +1,1718 @@ +/* + * ViLE - Visual Library Engine + * Copyright (c) 2010-2011, ViLE Team (team@vilevn.org) + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3 of the 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. + */ + +#include "windy.h" + +EngineWindy::EngineWindy(int Width,int Height) : EngineVN(Width,Height){ + // Set defaults + ssoffset=0x4000; + ssbuffer=0; + ssindex=0; + sslength=0; + lsoffset=0; + lsbuffer=0; + lsindex=0; + lslength=0; + tsindex=0; + csbuffer=lsbuffer; + csstack=&lsstack; + csindex=&lsindex; + cslength=&lslength; + csoffset=&lsoffset; + w_tv=0; + whisper=0; + sel_result=-1; + sel_flag=-1; + sel_address=0; + processastext=true; + tstype=WINDYSTUB_ERROR; + state=WINDYSTATE_NORMAL; + pausedstate=state; + Pause(); + + // Preallocate a good chunk of ram + vars.SetUint16(0xffff,0); + + // Assign standard widgets + w_bg=new Widget(); + w_bg->Move(0,0); + w_bg->Resize(Width,Height); + AddWidget(w_bg,VL_BACKGROUND); +} + +EngineWindy::~EngineWindy(){ + if(ssbuffer){ + delete [] ssbuffer; + } + if(lsbuffer){ + delete [] lsbuffer; + } + if(whisper){ + delete whisper; + } +} + +/*! \brief Loads a script with common subroutines + * \param Script Name of the script resource to load + * \param Entrypoint Offset to start parsing from (Usually NULL) + * \return TRUE if script was found and loaded + */ +bool EngineWindy::LoadWindyRoutines(uString Script,Uint16 Entrypoint){ + bool retval=false; + RWops *blob=0; + if((blob=LoadScript(Script))){ + // Extract and verify data + LogDebug("Loading routines: %s",Script.c_str()); + int tlength=blob->Seek(0,SEEK_END); + if(tlength>(int)0){ + // Replace blob + blob->Seek(0,SEEK_SET); + char *tbuffer=new char[tlength]; + if(blob->Read(tbuffer,tlength)>(int)0){ + // Find start + int start=0; + if(!strncmp(tbuffer,"WindySub",8)){ + // Skip the mumbojumbo part + start=256; + } + + // Decode input data + bool toggle=true; + for(int i=start;iSynchronize(EDL_Searchname(Script),stringlist); + } + + // Extract and verify data + LogDebug("Loading script: %s",Script.c_str()); + int tlength=blob->Seek(0,SEEK_END); + if(tlength>(int)0){ + // Replace blob + blob->Seek(0,SEEK_SET); + char *tbuffer=new char[tlength]; + if(blob->Read(tbuffer,tlength)>(int)0){ + // Find start + int start=0; + if(!strncmp(tbuffer,"WindySub",8)){ + LogError("Loading routines as script:%s",Script.c_str()); + start=256; + } + + // Decode input data + bool toggle=true; + for(int i=start;iFill(RGBA); +} + +Widget *EngineWindy::LoadSelection(Stringlist Strings, + Uint16 R1,Uint16 R2,Uint16 A1,Uint16 A2){ + return 0; +} + +Widget *EngineWindy::LoadSelection(Stringlist Strings){ + return 0; +} + +bool EngineWindy::Call(Uint16 Address){ + if(Address-*csoffset<*cslength){ + // Pass request to clients + bool process=false; + if(*csoffset==0){ + if(!EventInternal(Address)){ + process=true; + } + } + else{ + if(!EventExternal(Address)){ + process=true; + } + } + + // Process request ourselves + if(process){ + Uint16 *oldindex=new Uint16; + *oldindex=*csindex; + csstack->Push(oldindex); + *csindex=Address-*csoffset; + } + } + else if(csbuffer==lsbuffer){ + if(!EventExternal(Address)){ + // Shift to external routines + ssindex=Address-ssoffset; + csbuffer=ssbuffer; + csstack=&ssstack; + csindex=&ssindex; + cslength=&sslength; + csoffset=&ssoffset; + } + } + else{ + LogError("Invalid Call(0x%04x)",Address); + } + return false; +} + +/* + * Return from routine (Either internal or external) + */ +bool EngineWindy::Return(){ + if(csstack->Peek()){ + Uint16 *oldindex=(Uint16*)csstack->Pop(); + *csindex=*oldindex; + delete oldindex; + } + else if(csbuffer==ssbuffer){ + // Shift back to internal buffer + csbuffer=lsbuffer; + csstack=&lsstack; + csindex=&lsindex; + cslength=&lslength; + csoffset=&lsoffset; + } + else{ + LogError("Invalid return (0x%04x)",*csindex); + } + return false; +} + +bool EngineWindy::Jump(Uint16 Address){ + if(Address-*csoffset<*cslength){ + *csindex=Address-*csoffset; + } + else{ + LogError("Invalid jump: 0x%04x -> 0x%04x",Address,Address-*csoffset); + } + return false; +} + +/*! \brief Temporarily halts execution + * \return True if execution is paused + * + * This method should be used by derivated games to halt processing the + * native code until it has completed some specialized tasks (Such as the + * localization menu in nocturnal illusions. + * + * This method will fail if the engine is in a non-processingstate upon + * calling it (Except when already paused). + */ +bool EngineWindy::Pause(){ + if(state!=WINDYSTATE_WAITCLIENT){ + pausedstate=state; + state=WINDYSTATE_WAITCLIENT; + } + return (state==WINDYSTATE_WAITCLIENT); +} + +/*! \brief Resumes native code processing + * \return True if execution is running as normal + */ +bool EngineWindy::Resume(){ + if(state==WINDYSTATE_WAITCLIENT){ + state=pausedstate; + } + return (state==WINDYSTATE_NORMAL); +} + +Uint16 EngineWindy::GetValue(Uint16 Address){ + return vars.GetUint16(Address); +} + +void EngineWindy::SetValue(Uint16 Address,Uint16 Value){ + vars.SetUint16(Address,Value); +} + +void EngineWindy::SetSkipmode(bool Skip){ + EngineVN::SetSkipmode(Skip); + w_tv->SetSkipmode(Skip); +} + +void EngineWindy::SetMessageDelayEnabled(bool Enabled){ + EngineVN::SetMessageDelayEnabled(Enabled); + if(Enabled){ + w_tv->SetTextInterval((GetMessageDelayInterval()/100.0)*200); + } + else{ + w_tv->SetTextInterval(0); + } +} + +void EngineWindy::SetMessageDelayInterval(int Interval){ + EngineVN::SetMessageDelayInterval(Interval); + w_tv->SetTextInterval((GetMessageDelayInterval()/100.0)*200); +} + + +void EngineWindy::EventTextMode(Uint16 Mode,Uint16 X,Uint16 Y, + Uint16 Width,Uint16 Height,Uint16 Flag){ +} + +void EngineWindy::EventBlit(Uint16 Opcode,Uint16 Index){ +} + +/*! \brief Allows derived games to override special functions + * \param Address Address of external routine + * \return True if call was handled internally + * + * This can be used to override special functions such as setting date + * and time. These methods are often meaningless when emulating an updated + * version of the games. + * + * Base method always does nothing and returns false to allow the real + * method execute normally. + */ +bool EngineWindy::EventExternal(Uint16 Address){ + return false; +} + +bool EngineWindy::EventInternal(Uint16 Address){ + return false; +} + +void EngineWindy::EventSelect(int Selection){ + // Store result and resume processing + vars.SetUint16(sel_result,Selection+1); + vars.SetUint16(sel_flag,0); + if(sel_address){ + //Call(sel_address); + Jump(sel_address); + } + + // Free up widgets and return to processing + DestroyLayer(VL_CHOICES); + state=WINDYSTATE_NORMAL; +} + +bool EngineWindy::EventGameTick(){ + // Check for queued up textstubs + if(state==WINDYSTATE_WAITMORE){ + if(w_tv){ + bool skip=keyok || keyctrl() || GetSkipmode(); + if(skip && w_tv->GetRemainingText()){ + w_tv->CompleteText(); + keyok=false; + } + else if(skip){ + StopSound(VA_VOICES); + ProcessText(); + keyok=false; + } + } + } + + // Check for user input + if(state==WINDYSTATE_WAITCLICK){ + if(w_tv){ + bool skip=keyok || keyctrl() || GetSkipmode(); + if(skip && w_tv->GetRemainingText()){ + w_tv->CompleteText(); + keyok=false; + } + else if(skip){ + StopSound(VA_VOICES); + state=WINDYSTATE_NORMAL; + keyok=false; + } + } + } + + // Process only when all text is printed in normal state + return !(state==WINDYSTATE_NORMAL && !w_tv->GetRemainingText()); +} + +void EngineWindy::EventNew(){ + vars.Clear(); + StopMusic(); + StopSound(); + w_tv->CompleteText(); + w_tv->ClearText(); + DestroyLayer(VL_CHOICES); + sel_strings.Clear(); +} + +bool EngineWindy::EventLoad(int Index){ + bool retval=false; + Savegame *load=new Savegame(NativeID(),Index); + if(load->Read()){ + // Clear existing data + EngineWindy::EventNew(); + + // Load script data + load->LoadVector("variables",&vars); + load->LoadString("scriptname",&lsname); + load->LoadUint32("scriptpos",&lsindex); + LoadWindyScript(lsname,lsindex); + state=WINDYSTATE_NORMAL; + + // Load text data + Uint8 tmpval; + uString tmpstring; + load->LoadUint32("textpos",&tsindex); + load->LoadUint8("texttype",&tmpval); + tstype=(WINDY_STUBTYPE)tmpval; + + // Load dynamic strings + stringlist.Clear(); + load->LoadStringList("stringlist",&stringlist); + + // Load graphics + SDL_Surface *tmps; + if(load->LoadSurface("screen-display",&tmps)){ + w_bg->Blit(tmps); + SDL_FreeSurface(tmps); + } + + // Close dialog + retval=true; + } + delete load; + return retval; +} + +bool EngineWindy::EventSave(int Index){ + // Gather date string + uString date=EDL_DateString(EDL_UnixTime()); + uString time=EDL_TimeString(EDL_UnixTime()); + uString datetime=date+uString(" ")+time; + + // Store script data + Savegame *save=new Savegame(NativeID(),Index); + save->SaveString("scriptname",lsname); + save->SaveUint32("scriptpos",saveindex); + save->SaveVector("variables",&vars); + save->SaveString("savedate",datetime.c_str()); + + // Store text data + save->SaveUint32("textpos",tsindex); + save->SaveUint8("texttype",tstype); + + // Store dynamic strings + save->SaveStringList("stringlist",&stringlist); + + // Store graphics + SDL_Surface *screen=EDL_CreateSurface(NativeWidth(),NativeHeight()); + Paint(screen,VL_CHOICES); + save->SaveSurface("screen-thumb",screen,96,72); + Paint(screen,VL_CHARACTERS); + save->SaveSurface("screen-display",screen); + SDL_FreeSurface(screen); + + // Close dialogs + save->Write(); + delete save; + return true; +} + +bool EngineWindy::EventGameProcess(){ + bool retval=true; + if(state==WINDYSTATE_NORMAL && csindex && *csindex<*cslength){ + // Parse word + Uint16 opcode=GETWORD(csbuffer+*csindex); + LogDebug("Processing opcode %04x:%04x",*csindex,opcode); + *csindex+=2; + + // Believed-to-be-identified opcodes + if(opcode==0x0002) retval=OP0002(); + else if(opcode==0x0003) retval=OP0003(); + else if(opcode==0x000A) retval=OP000A(); + else if(opcode==0x000B) retval=OP000B(); + else if(opcode==0x000C) retval=OP000C(); + else if(opcode==0x0013) retval=OP0013(); + else if(opcode==0x0014) retval=OP0014(); + else if(opcode==0x0015) retval=OP0015(); + else if(opcode==0x0018) retval=OP0018(); + else if(opcode==0x0019) retval=OP0019(); + else if(opcode==0x001A) retval=OP001A(); + else if(opcode==0x001C) retval=OP001C(); + else if(opcode==0x001F) retval=OP001F(); + else if(opcode==0x0021) retval=OP0021(); + else if(opcode==0x0022) retval=OP0022(); + else if(opcode==0x0024) retval=OP0024(); + else if(opcode==0x0025) retval=OP0025(); + else if(opcode==0x0027) retval=OP0027(); + else if(opcode==0x002D) retval=OP002D(); + else if(opcode==0x002F) retval=OP002F(); + else if(opcode==0x0038) retval=OP0038(); + else if(opcode==0x003A) retval=OP003A(); + else if(opcode==0x003E) retval=OP003E(); + else if(opcode==0x003F) retval=OP003F(); + else if(opcode==0x0040) retval=OP0040(); + else if(opcode==0x0041) retval=OP0041(); + else if(opcode==0x0042) retval=OP0042(); + else if(opcode==0x0043) retval=OP0043(); + else if(opcode==0x004A) retval=OP004A(); + else if(opcode==0x004B) retval=OP004B(); + else if(opcode==0x004F) retval=OP004F(); + else if(opcode==0x0051) retval=OP0051(); + else if(opcode==0x0052) retval=OP0052(); + else if(opcode==0x0053) retval=OP0053(); + else if(opcode==0x0054) retval=OP0054(); + else if(opcode==0x0055) retval=OP0055(); + else if(opcode==0x0059) retval=OP0059(); + else if(opcode==0x005A) retval=OP005A(); + else if(opcode==0x005E) retval=OP005E(); + else if(opcode==0x0060) retval=OP0060(); + else if(opcode==0x0062) retval=OP0062(); + else if(opcode==0x0063) retval=OP0063(); + else if(opcode==0x0064) retval=OP0064(); + else if(opcode==0x006E) retval=OP006E(); + else if(opcode==0x007B) retval=OP007B(); + else if(opcode==0x0080) retval=OP0080(); + else if(opcode==0x008F) retval=OP008F(); + else if(opcode==0x0095) retval=OP0095(); + //else if(opcode==0x0096) retval=OP0096(); + + // Unknown opcodes (Needed for correct parsing) + else if(opcode==0x0004){ + *csindex+=2; + } + else if(opcode==0x0007){ + *csindex+=4; + } + else if(opcode==0x0008){ + *csindex+=4; + } + else if(opcode==0x0012){ + *csindex+=2; + } + else if(opcode==0x001E){ + *csindex+=2; + } + else if(opcode==0x0072){ + *csindex+=2; + } + else if(opcode==0x0076){ + *csindex+=16; + } + else if(opcode==0x0077){ + *csindex+=16; + } + else if(opcode==0x0093){ + *csindex+=2; + } + else if(opcode==0x0096){ + *csindex+=4; + } + + // Report unknown + else{ + LogDebug("%04x:UNKNOWN: 0x%04x",*csindex-2,opcode); + } + } + + // Check wether state was retained + if(state!=WINDYSTATE_NORMAL){ + retval=true; + } + return retval; +} + +bool EngineWindy::OP0002(){ + // Extract parameters + //Uint16 p1=GETWORD(csbuffer+*csindex+0); + //Uint16 p2=GETWORD(csbuffer+*csindex+2); + //Uint16 p3=GETWORD(csbuffer+*csindex+4); + Uint16 p4=GETWORD(csbuffer+*csindex+6); // Target surface? + Uint16 p5=GETWORD(csbuffer+*csindex+8); // Image filename + Uint16 p6=GETWORD(csbuffer+*csindex+10); // Transparancy 0/1? + //Uint16 p7=GETWORD(csbuffer+*csindex+12); // Always 1? + *csindex+=14; + + // Set resource name + uString name; + if(p5>ssoffset){ + name=(char*)ssbuffer+1+(p5-ssoffset); + } + else{ + name=(char*)lsbuffer+1+p5; + } + + // Load resource + if(name.length()){ + if(LoadGraphics(name,p4,p6)){ + UnlockCG(name); + } + } + else{ + LogError("Invalid bitmap reference: %04x",p5); + } + return false; +} + +/* + * Configures text output (Includes option for old versions) + * + * Before options: + * 000C 0000 000A 0009 0008 0001 + * + * Before text: + * 0003 0003 0013 0022 0006 0000 + * + * Before quote: + * 0003 0007(X) 000A(Y) 001E(W) 0004(H) 0000 + */ +bool EngineWindy::OP0003(){ + // Process data + Uint16 p1=GETWORD(csbuffer+*csindex+0); // Type or subcommand + Uint16 p2=GETWORD(csbuffer+*csindex+2); // X Coordinate + Uint16 p3=GETWORD(csbuffer+*csindex+4); // Y Coordinate + Uint16 p4=GETWORD(csbuffer+*csindex+6); // Width in characters + Uint16 p5=GETWORD(csbuffer+*csindex+8); // Height in characters + Uint16 p6=GETWORD(csbuffer+*csindex+10); // Clickable flag? + *csindex+=12; + + // Pass gui change + EventTextMode(p1,p2,p3,p4,p5,p6); + return false; +} + +/*! \brief Executes an unconditional jump instruction to its argument + * \return False + */ +bool EngineWindy::OP000A(){ + Uint16 p1=GETWORD(csbuffer+*csindex+0); + *csindex+=2; + Jump(p1); + return false; +} + +/* If-then blocks for comparing two registers + */ +bool EngineWindy::OP000B(){ + // Extract parameters + Uint16 p1=GETWORD(csbuffer+*csindex+0); + Uint16 p2=GETWORD(csbuffer+*csindex+2); + Uint16 p3=GETWORD(csbuffer+*csindex+4); + Uint16 p4=GETWORD(csbuffer+*csindex+6); + *csindex+=8; + Sint16 v1=vars.GetSint16(p1); + Sint16 v2=vars.GetSint16(p2); + + // Check operator + if(p3==0x000D){ + // Equal? + if(v1==v2){ + *csindex=p4-*csoffset; + } + } + else if(p3==0x000E){ + if(v1v2){ + *csindex=p4-*csoffset; + } + } + else if(p3==0x0010){ + if(v1<=v2){ + *csindex=p4-*csoffset; + } + } + else if(p3==0x0011){ + if(v1>=v2){ + *csindex=p4-*csoffset; + } + } + else if(p3==0x0012){ + // Not equal? + if(v1!=v2){ + *csindex=p4-*csoffset; + } + } + else{ + LogError("Invalid IF operator: 0x%04x",p3); + } + return false; +} + +/* If-then blocks for comparing a register to an intermediate + */ +bool EngineWindy::OP000C(){ + // Extract parameters + Uint16 p1=GETWORD(csbuffer+*csindex+0); + Sint16 p2=GETWORD(csbuffer+*csindex+2); // Must be signed! + Uint16 p3=GETWORD(csbuffer+*csindex+4); + Sint16 p4=GETWORD(csbuffer+*csindex+6); + *csindex+=8; + Sint16 v=vars.GetSint16(p1); + + // Check operator + if(p3==0x000D){ + // Equal? + if(v==p2){ + *csindex=p4-*csoffset; + } + } + else if(p3==0x000E){ + if(vp2){ + *csindex=p4-*csoffset; + } + } + else if(p3==0x0010){ + if(v<=p2){ + *csindex=p4-*csoffset; + } + } + else if(p3==0x0011){ + if(v>=p2){ + *csindex=p4-*csoffset; + } + } + else if(p3==0x0012){ + // Not equal? + if(v!=p2){ + *csindex=p4-*csoffset; + } + } + else if(p3==0x0018){ + // This is probably a dirty hack + // Necessary to ge through nocturnal illusion script 8_30.S + if(v!=p2){ + *csindex-=4; + } + else{ + *csindex+=2; + } + } + else{ + LogError("Invalid IF operator: 0x%04x (%x %x)",p3,v,p2); + } + return false; +} + +/* Executes switch-case jumps in tables of absolute byte positions + * + * The first parameter probably reffers to some sort of register or + * variable which in turn refers a system parameter. Had to implement + * this half-assed version to act upon selections. + */ +bool EngineWindy::OP0013(){ + // Extract jump offset + Uint16 p1=GETWORD(csbuffer+*csindex+0); + *csindex+=2; + + // Extract variable and jump according to the result + Uint16 v=vars.GetUint16(p1); + if((*csindex+(v*2))<*cslength){ + Uint16 p=GETWORD(csbuffer+*csindex+(v*2)); + if(p-*csoffset<*cslength){ + *csindex=p-*csoffset; + } + else{ + LogError("%04x:Invalid switch jump: var[0x%04x]=0x%04x=>0x%04x", + *csindex-4,p1,v,p); + } + } + else{ + LogError("%04x:Invalid switch value: var[0x%x]=0x%x",*csindex-4,p1,v); + } + return false; +} + +bool EngineWindy::OP0014(){ + //Uint16 p1=GETWORD(csbuffer+*csindex+0); + //Uint16 p2=GETWORD(csbuffer+*csindex+2); + //Uint16 p3=GETWORD(csbuffer+*csindex+4); + //Uint16 p4=GETWORD(csbuffer+*csindex+6); + *csindex+=8; + return false; +} + +/* Loads addressed text stubs (Both text and selection options) + */ +bool EngineWindy::OP0015(){ + // Parse input + Uint16 p1=GETWORD(csbuffer+*csindex+0); + Uint16 p2=GETWORD(csbuffer+*csindex+2); + *csindex+=4; + if(p2-*csoffset<*cslength){ + // Process stub as either text or option/menu + tsindex=p2; + if(processastext){ + LogDebug("Processing stubs as text ..."); + ProcessText(); + } + else{ + LogDebug("Processing stubs as options ..."); + ProcessOptions(); + } + } + else{ + LogError("%04x:Invalid text stub: %04x %04x",*csindex-6,p1,p2); + } + return false; +} + +/* Assigns an intermediate to a register + */ +bool EngineWindy::OP0018(){ + Uint16 p1=GETWORD(csbuffer+*csindex+0); + Uint16 p2=GETWORD(csbuffer+*csindex+2); + *csindex+=4; + vars.SetUint16(p1,p2); + return false; +} + +/* Assigns a register to another register + */ +bool EngineWindy::OP0019(){ + Uint16 p1=GETWORD(csbuffer+*csindex+0); + Uint16 p2=GETWORD(csbuffer+*csindex+2); + Uint16 v2=vars.GetUint16(p2); + *csindex+=4; + vars.SetUint16(p1,v2); + return false; +} + +/*! \brief Loads a named bgm resource + */ +bool EngineWindy::OP001A(){ + Uint16 p1=GETWORD(csbuffer+*csindex+0); + *csindex+=2; + char b[12]; + strncpy(b,(char*)csbuffer+(p1-*csoffset),12); + if(p1-*csoffset<*cslength){ + if(!PlayMusic(b+1)){ + LogError("Could not resolve BGM: %s",b+1); + } + } + else{ + LogError("%04x:Invalid bgm resource: 0x%04x",*csindex-4,p1); + } + return false; +} + +/* + * Stops running track? + */ +bool EngineWindy::OP001C(){ + StopMusic(); + return false; +} + +/* Loads a named script resource + */ +bool EngineWindy::OP001F(){ + Uint16 p1=GETWORD(csbuffer+*csindex+0); + *csindex+=2; + char b[12]; + strncpy(b,(char*)csbuffer+p1-*csoffset,12); + LogDebug("%04x:Loading script: %s (0x%02x)",*csindex-4,b+1,b[0]); + if(p1-*csoffset<*cslength && LoadWindyScript(b+1)){ + } + else{ + LogError("%04x:Invalid script resource: 0x%04x (%s)",*csindex-4,p1,b+1); + } + return false; +} + +/* Might be a be a decrement..might very well be not + */ +bool EngineWindy::OP0021(){ + //Uint16 p1=GETWORD(csbuffer+*csindex+0); + *csindex+=2; + return false; +} + +/* Might be a be an increment..might very well be not + */ +bool EngineWindy::OP0022(){ + // Parse input + Uint16 p1=GETWORD(csbuffer+*csindex+0); + *csindex+=2; + if(p1==0x03E8){ + // Enter option mode + LogDebug("%04x:Preparing state:0022 %04x",*csindex-4,p1); + processastext=false; + + // Savepoint for selections + if(!lsstack.Count() && !ssstack.Count()){ + saveindex=lsindex-4; + } + } + else if(p1==0x0120){ + LogDebug("%04x:Preparing state:0022 %04x",*csindex-4,p1); + processastext=true; + } + else{ + LogError("Unknown state: 0x%x",p1); + } + return false; +} + +/* Adds an intermediate to a register + */ +bool EngineWindy::OP0024(){ + Uint16 p1=GETWORD(csbuffer+*csindex+0); + Sint16 p2=GETWORD(csbuffer+*csindex+2); + *csindex+=4; + Sint16 v=vars.GetSint16(p1); + vars.SetSint16(p1,v+p2); + return false; +} + +/* Substracts an intermediate from a register + */ +bool EngineWindy::OP0025(){ + Uint16 p1=GETWORD(csbuffer+*csindex+0); + Sint16 p2=GETWORD(csbuffer+*csindex+2); + *csindex+=4; + Sint16 v=vars.GetSint16(p1); + vars.SetSint16(p1,v-p2); + return false; +} + +/* This is a rather dubious one ... + */ +bool EngineWindy::OP0027(){ + Uint16 p1=GETWORD(csbuffer+*csindex+0); + Uint16 p2=GETWORD(csbuffer+*csindex+2); + *csindex+=4; + Sint16 v1=vars.GetSint16(p1); + Sint16 v2=vars.GetSint16(p2); + vars.SetSint16(p1,v1+v2); + return false; +} + +/* + * Clears a range of variables by setting them to null + */ +bool EngineWindy::OP002D(){ + Uint16 p1=GETWORD(csbuffer+*csindex+0); + Uint16 p2=GETWORD(csbuffer+*csindex+2); + *csindex+=4; + for(int i=p1;i>16)&0xFFFF); + vars.SetSint16(p2,v3&0xFFFF); + return false; +} + +/* + * Loads a selection dialog. The last two parameter can either be jumps or + * calls, not sure, both seemingly works. + */ +bool EngineWindy::OP0040(){ + Uint16 p1=GETWORD(csbuffer+*csindex+0); // Register selection result? + Uint16 p2=GETWORD(csbuffer+*csindex+2); // Register mouse click? +#ifdef VILE_LOGGING_DEBUG + Uint16 p3=GETWORD(csbuffer+*csindex+4); // Routine for rightclick? +#endif + Uint16 p4=GETWORD(csbuffer+*csindex+6); // Routine for leftclick? + *csindex+=8; + LogDebug("%04x:Loading options: 0x%04x 0x%04x 0x%04x 0x%04x", + *csindex-10,p1,p2,p3,p4); + + // Change state and load selection menu + sel_result=p1; + sel_flag=p2; + sel_address=p4; + state=WINDYSTATE_SELECT; + AddWidget(LoadSelection(sel_strings),VL_CHOICES); + sel_strings.Clear(); + return false; +} + +/* + * Same as 0040, but for graphical menues + * + * This is only used for the location menu under nocturnal illusions + */ +bool EngineWindy::OP0041(){ + Uint16 p1=GETWORD(csbuffer+*csindex+0); // Register selection result? + Uint16 p2=GETWORD(csbuffer+*csindex+2); // Register mouse click? + Uint16 p3=GETWORD(csbuffer+*csindex+4); + Uint16 p4=GETWORD(csbuffer+*csindex+6); // Routine for mouseover? + *csindex+=8; + LogDebug("%04x:Loading location: 0x%04x 0x%04x 0x%04x 0x%04x", + *csindex-10,p1,p2,p3,p4); + + // Change state and load selection menu + sel_result=p1; + sel_flag=p2; + sel_address=p4; + state=WINDYSTATE_SELECT; + AddWidget(LoadSelection(sel_strings,p1,p2,p3,p4),VL_CHOICES); + sel_strings.Clear(); + return false; +} + +bool EngineWindy::OP0042(){ + *csindex+=2; + return false; +} + +/* + * This might pull results off "windows" such as location control in ni. + */ +bool EngineWindy::OP0043(){ + *csindex+=4; + return false; +} + +bool EngineWindy::OP004A(){ + *csindex+=4; + return false; +} + +/* + * Reads binary data (variables) from a file + */ +bool EngineWindy::OP004B(){ + Uint16 p1=GETWORD(csbuffer+*csindex+0); + Uint16 p2=GETWORD(csbuffer+*csindex+2); + *csindex+=4; + if(p2+1-*csoffset<*cslength){ + RWops *blob=LoadOther((char*)csbuffer+1+p2-*csoffset); + if(blob){ + int l=blob->Seek(0,SEEK_END); + blob->Seek(0,SEEK_SET); + Uint8 b[l]; + if(blob->Read(b,l)>(int)0){ + for(int i=0;iMove(v1*10,v2*10); + return true; +} + +/* + * Seem to be some kind of a blitter. The last two parameters might be + * bitmask, the other looks more like offsets and indexes. + */ +bool EngineWindy::OP0063(){ + Uint16 p1=GETWORD(csbuffer+*csindex+0); // Index for kilde? + //Uint16 p2=GETWORD(csbuffer+*csindex+2); // Flagg eller subkommando?? + //Uint16 p3=GETWORD(csbuffer+*csindex+4); // Flagg?? + //Uint16 p4=GETWORD(csbuffer+*csindex+6); // Lavt integer? + //Uint16 p5=GETWORD(csbuffer+*csindex+8); // Hoyde? + //Uint16 p6=GETWORD(csbuffer+*csindex+10); + //Uint16 p7=GETWORD(csbuffer+*csindex+12); // Koordinat? + //Uint16 p8=GETWORD(csbuffer+*csindex+14); // Koordinat? + *csindex+=16; + EventBlit(0x0063,p1); + return false; +} + +bool EngineWindy::OP0064(){ + Uint16 p1=GETWORD(csbuffer+*csindex+0); + //Uint16 p2=GETWORD(csbuffer+*csindex+2); + //Uint16 p3=GETWORD(csbuffer+*csindex+4); + //Uint16 p4=GETWORD(csbuffer+*csindex+6); + //Uint16 p5=GETWORD(csbuffer+*csindex+8); + //Uint16 p6=GETWORD(csbuffer+*csindex+10); + //Uint16 p7=GETWORD(csbuffer+*csindex+12); + //Uint16 p8=GETWORD(csbuffer+*csindex+14); + Uint16 v1=vars.GetUint16(p1); + *csindex+=16; + EventBlit(0x0064,v1); + return false; +} + +bool EngineWindy::OP006E(){ + Uint16 p1=GETWORD(csbuffer+*csindex+0); + Uint16 p2=GETWORD(csbuffer+*csindex+2); + *csindex+=4; + uString s1=stringlist.GetString(p1); + uString s2=stringlist.GetString(p2); + LogDebug("%04x:STRING:LENGTH: vars[%x]={%s}=%d", + *csindex-6,p1,s2.c_str(),s2.length()); + stringlist.SetString(p1,s2); + vars.SetUint16(p1,s2.length()); + return false; +} + +bool EngineWindy::OP007B(){ + *csindex+=4; + return false; +} + +/* + * Load string resources such as names and uses them as keys for the inifile + */ +bool EngineWindy::OP0080(){ + Uint16 p1=GETWORD(csbuffer+*csindex+0); + Uint16 p2=GETWORD(csbuffer+*csindex+2); + *csindex+=4; + if(p2-*csoffset<*cslength){ + LogDebug("%04x:STRING:INI:%04x=%04x=%s", + *csindex-6,p1,p2,csbuffer+1+p2-*csoffset); + stringlist.SetString(p1,(char*)csbuffer+1+p2-*csoffset); + stringlist.SetString(p1+1,"Shinichi"); + //vars.SetUint16(p1,stringlist.GetString(p1).length()); + //vars.SetUint16(p1+1,stringlist.GetString(p1+1).length()); + } + else{ + LogError("%04x:Invalid string ini:%04x %04x",*csindex-6,p1,p2); + } + return false; +} + +/* Loads a named script resource + */ +bool EngineWindy::OP008F(){ + Uint16 p1=GETWORD(csbuffer+*csindex+0); + Uint16 p2=GETWORD(csbuffer+*csindex+2); + *csindex+=4; + char b[12]; + strncpy(b,(char*)csbuffer+p2-*csoffset,12); + LogDebug("%04x:Loading routines: %s (0x%02x)",*csindex-4,b+1,b[0]); + if(p2-*csoffset<*cslength && LoadWindyRoutines(b+1)){ + } + else{ + LogError("%04x:Invalid routines: 0x%04x",*csindex-4,p1); + } + return false; +} + +/* + * Blitter that is mostly used in nocturnal illusion. Seems to blit a image + * (either opaque or transparent) from the first buffer to the display. + * + * Strangely, it seems like the source is deleted upon using this blitter. + */ +bool EngineWindy::OP0095(){ + Uint16 p1=GETWORD(csbuffer+*csindex+0); // Always 0? + //Uint16 p2=GETWORD(csbuffer+*csindex+2); // Always 0? + //Uint16 p3=GETWORD(csbuffer+*csindex+4); // X Coordinate + //Uint16 p4=GETWORD(csbuffer+*csindex+6); // Width + //Uint16 p5=GETWORD(csbuffer+*csindex+8); + //Uint16 p6=GETWORD(csbuffer+*csindex+10); + //Uint16 p7=GETWORD(csbuffer+*csindex+12); + //Uint16 p8=GETWORD(csbuffer+*csindex+14); + *csindex+=16; + EventBlit(0x0095,p1); + return false; +} + +bool EngineWindy::OP0096(){ + Uint16 p1=GETWORD(csbuffer+*csindex+0); + //Uint16 p2=GETWORD(csbuffer+*csindex+2); + //Uint16 p3=GETWORD(csbuffer+*csindex+4); + //Uint16 p4=GETWORD(csbuffer+*csindex+6); + //Uint16 p5=GETWORD(csbuffer+*csindex+8); + //Uint16 p6=GETWORD(csbuffer+*csindex+10); + //Uint16 p7=GETWORD(csbuffer+*csindex+12); + //Uint16 p8=GETWORD(csbuffer+*csindex+14); + //Uint16 p9=GETWORD(csbuffer+*csindex+16); + //Uint16 p10=GETWORD(csbuffer+*csindex+18); + //Uint16 p11=GETWORD(csbuffer+*csindex+20); + *csindex+=22; + EventBlit(0x0096,p1); + return false; +} + +/*! \brief Processes text from csbuffer[tsindex] + * \return True if options was successfully parsed + */ +bool EngineWindy::ProcessOptions(){ + bool retval=true; + int tsstart=tsindex; + uString ptext; + while(tsindex<*cslength && csbuffer[tsindex]){ + if(csbuffer[tsindex]==0x0F){ + // Inline ascii is not supported + tsindex++; + tsindex++; + } + else if(csbuffer[tsindex]==0x1B){ + // Exchange constants + Uint16 ref=csbuffer[tsindex++]; + ref=csbuffer[tsindex++]; + uString ttext=stringlist.GetString(ref); + LogDebug("Appending string: %d=[%s]",ref,ttext.c_str()); + ptext+=ttext; + } + else if(csbuffer[tsindex]<0x0D){ + // Drop control data + LogDebug("Dropping control character:%x",csbuffer[tsindex]); + tsindex++; + } + else{ + // Accumelate data + ptext+=(char)csbuffer[tsindex++]; + } + } + + + // Build selection dialog + if(ptext.length()){ + // Parse selection captions + int selcount=sel_strings.GetCount(); + unsigned int start=0; + for(unsigned int i=0;i0){ + uString tmpstring=ptext.substr(start,i-start); + sel_strings.SetString(selcount++,tmpstring); + } + start=i+1; + } + } + if(startClearText(); + } + + // Register current text type + tstype=(WINDY_STUBTYPE)res; + if(tstype!=WINDYSTUB_DEFAULT){ + state=WINDYSTATE_WAITMORE; + } + + // Load voice if any + if(whisper){ + uString voice=whisper->GetVoice(tsstart); + if(voice.length()){ + PlayVoice(voice); + } + } + + // Detect quoted names + if(ptext[0]==(char)0x5B){ + // Assert clear screen when printing conversations + w_tv->ClearText(); + + // Find endquote and print name immidiatly + for(unsigned int i=1;iPrintText(ptext.substr(0,i+1)); + w_tv->CompleteText(); + ptext=ptext.substr(i+1); + break; + } + } + } + + // Print remaining text normally + w_tv->PrintText(ptext); + + // Store position + if(!lsstack.Count() && !ssstack.Count()){ + saveindex=lsindex-6; + } + } + return tstype; +} + +/*! \brief Parses text from a decoded script + * \param String Where to place extracted data + * \return See WINDY_STUBTYPE + */ +WINDY_STUBTYPE EngineWindy::ParseText(uString *String){ + WINDY_STUBTYPE retval=WINDYSTUB_ERROR; + if(String && tsindex<*cslength){ + // Parse string and datatype + (*String)=""; + retval=WINDYSTUB_DEFAULT; + while(1){ + if(csbuffer[tsindex]<=WINDYSTUB_SELECTION){ + // Handle inline command + retval=(WINDY_STUBTYPE)csbuffer[tsindex++]; + break; + } + else if(csbuffer[tsindex]==WINDYSTUB_CONSTANT){ + // Change constant with name + uString str=stringlist.GetString(csbuffer[tsindex+1]); + if(!str.length()){ + str="Shinichi"; + } + (*String)+=str; + tsindex++; + tsindex++; + } + else if(csbuffer[tsindex]==0x0F){ + // Think this is some kind of inline ascii codes + (*String)+=' '; + tsindex++; + tsindex++; + } + else if(csbuffer[tsindex]>'~'){ + Uint16 gaiji=GETWORD(csbuffer+tsindex); + tsindex+=2; + if(gaiji==0xB4EB){ + (*String)+="!!"; + } + else if(gaiji==0xB5EB){ + (*String)+="!"; + } + else if(gaiji==0xB6EB){ + (*String)+="?"; + } + else if(gaiji==0xB8EB){ + (*String)+="!!"; // Actually with droplets ... + } + else if(gaiji==0xC1EB){ + (*String)+="!?"; + } + else if(gaiji==0xC2EB){ + (*String)+="!!"; + } + else if(gaiji==0xC3EB){ + (*String)+="??"; + } + else if(gaiji==0xC3EB){ + (*String)+=".."; // Actually with droplets ... + } + + else{ + LogDebug("\tUnknown gaiji:%04x",gaiji); + } + } + else if(csbuffer[tsindex]==0x1B){ + // Exchange constants + Uint16 ref=csbuffer[tsindex++]; + ref=csbuffer[tsindex++]; + uString ttext=stringlist.GetString(ref); + LogDebug("Appending string: %d=%s",ref,ttext.c_str()); + (*String)+=ttext; + } + else if(csbuffer[tsindex]>='\t' && csbuffer[tsindex]<='~'){ + // Accumelate buffer + (*String)+=(char)csbuffer[tsindex++]; + } + else{ + // Drop unrecognized code + LogDebug("Unknown text code: 0x%02x",csbuffer[tsindex]); + tsindex++; + } + } + + // Assert returnvalue + if(retval>WINDYSTUB_WAITFORUSER){ + retval=WINDYSTUB_ERROR; + } + if(retval==WINDYSTUB_ERROR && String->length()){ + LogError("Dropping errenous text:%s",String->c_str()); + (*String)=""; + } + } + return retval; +} + + diff --git a/engines/vileVN/windy/windy.h b/engines/vileVN/windy/windy.h new file mode 100644 index 0000000000..39b9cd54b5 --- /dev/null +++ b/engines/vileVN/windy/windy.h @@ -0,0 +1,193 @@ +/*! \class EngineWindy + * \brief Windy game engine + * + * The windy engine uses a wordcode interpreter to drive the game. Tbe kink + * with this system is that it allocates common routines in a different + * script. It also calls routines from both internal and external routines, + * making a stacking mechanism necesary for both handlers. + * + * This implementation covers this by accessing the "current script resource" + * from a set of pointers; These pointers can point to either the resources + * for common routines (ssxxxxx) or the currently loaded resource (lsxxxxx). + * + * The engine is currently rough on systemrelated commands, but works quite + * well using macros instead of the external methods (which holds most of the + * systemcalls). + * + * The Windy engine is not UNICODE compliant as it only supports two games. + */ +#ifndef _WINDY_H_ +#define _WINDY_H_ + +#include "../engine/evn.h" +#include "whisper.h" + +#define GETWORD(B) ((B)[0]|((B)[1]<<8)) + +enum WINDY_STATE { //!< State of engine + WINDYSTATE_NORMAL, //!< Normal processing state + WINDYSTATE_SELECT, //!< Wait for user selection + WINDYSTATE_WAITMORE, //!< Wait for user then process more text + WINDYSTATE_WAITCLICK, //!< Wait for user then return to normal + WINDYSTATE_WAITCLIENT //!< Wait for game derivate to resume code +}; + +enum WINDY_STUBTYPE { + WINDYSTUB_ERROR= -1, //!< Could not read stub + WINDYSTUB_DEFAULT= 0x00, //!< Null-terminated string + WINDYSTUB_CLEARSCREEN= 0x01, //!< Clear screen after text completes + WINDYSTUB_WAITFORUSER= 0x02, //!< Print next after text completes + WINDYSTUB_SELECTION= 0x03, //!< CR Terminated lines for selection + WINDYSTUB_CONSTANT= 0x04 //!< Constant (for names etc) +}; + +class EngineWindy : public EngineVN { + private: + // Common subroutines + Uint8 *ssbuffer; //!< Holds current script data + Uint32 ssindex; //!< Current script code position + Uint32 sslength; //!< Length of current script data + Uint32 ssoffset; //!< Offset from given index + DStack ssstack; //!< Tracks code position through calls + + // Loaded script resource + uString lsname; //!< Name of loaded script + Uint8 *lsbuffer; //!< Holds loaded script data + Uint32 lsindex; //!< Code position for loaded script + Uint32 lslength; //!< Length of loaded script data + Uint32 lsoffset; //!< Offset from given index + DStack lsstack; //!< Stack mechanism for loaded script + + // Current script resource + Uint8 *csbuffer; //!< Holds current script data + Uint32 *csindex; //!< Current script code position + Uint32 *cslength; //!< Length of current script data + Uint32 *csoffset; //!< Offset from given index + DStack *csstack; //!< Tracks code position through calls + + // Selection data + Stringlist sel_strings; //!< Hold selection menu strings + Uint16 sel_result; //!< Holds register for selection result + Uint16 sel_flag; //!< Holds register for selection flag + Uint16 sel_address; //!< Address to call(?) upon completion + + // Other Engine data + WINDY_STUBTYPE tstype; //!< Current text type (Cls,etc) + Uint32 tsindex; //!< Current text position (In script) + WINDY_STATE state; //!< Current state + WINDY_STATE pausedstate; //!< State to resume to + Stringlist stringlist; //!< Hold allocated strings + Uint32 saveindex; //!< Holds index for saving + + // Text processing + WINDY_STUBTYPE ParseText(uString *String); + WINDY_STUBTYPE ProcessText(); + bool ProcessOptions(); + bool processastext; + protected: + // Opcode handlers + bool OP0002(); // Set background(?) graphics + bool OP0003(); + bool OP000A(); // Unconditional jump + bool OP000B(); // If(var==var) + bool OP000C(); // If(var==int) + bool OP0013(); // Switch/case + bool OP0014(); + bool OP0015(); // Process text stub? + bool OP0018(); // Stores intermediate value + bool OP0019(); // Stores register value + bool OP001A(); // Load named bgm resource + bool OP001C(); // Stop running bgm + bool OP001F(); // Load named script + bool OP0021(); + bool OP0022(); // Changes state???? + bool OP0024(); // Add intermediate to variable + bool OP0025(); // Substract intermediate from variable + bool OP0027(); // Substract variable from variable + bool OP002D(); + bool OP002F(); // Blitter? + bool OP0038(); // And registers? + bool OP003A(); + bool OP003E(); // Divides registers + bool OP003F(); + bool OP0040(); // Store system variables? + bool OP0041(); // Store system variables? + bool OP0042(); + bool OP0043(); + bool OP004A(); + bool OP004B(); // Load binary data + bool OP004F(); // Play sound effect + bool OP0051(); // AND register with intermediate + bool OP0052(); // OR register with intermediate + bool OP0053(); + bool OP0054(); // Call subroutines + bool OP0055(); // Return from subroutines + bool OP0059(); // Load string resources + bool OP005A(); // Clear string resources + bool OP005E(); + bool OP0060(); // Open external files (Legacy savegames) + bool OP0062(); // Move background + bool OP0063(); // Blitter? + bool OP0064(); // Blitter? + bool OP006E(); // Calculates string length + bool OP007B(); + bool OP0080(); // Load values from inifile + bool OP008F(); // Load subroutines + bool OP0095(); // Blitter + bool OP0096(); // Blitter? + DVector vars; // Holds values + + // Widgets + Widget *w_bg; //!< Holds background graphics + Textview *w_tv; + + // Voice synchronization + Whisper *whisper; + public: + EngineWindy(int Width,int Height); + ~EngineWindy(); + + // Special windy events + virtual void EventTextMode(Uint16 Mode,Uint16 X,Uint16 Y, + Uint16 Width,Uint16 Height,Uint16 Flag); + virtual void EventBlit(Uint16 Opcode,Uint16 Index); + virtual bool EventExternal(Uint16 Address); + virtual bool EventInternal(Uint16 Address); + + // Windy support methods + virtual bool LoadWindyScript(uString Script,Uint16 Entrypoint=0); + virtual bool LoadWindyRoutines(uString Script,Uint16 Entrypoint=0); + virtual bool LoadGraphics(uString Name,Uint16 Index,Uint16 Type); + virtual void FillGraphics(Uint16 Index); + virtual void FillBackground(Uint32 RGBA); + virtual Widget *LoadSelection(Stringlist Strings); + virtual Widget *LoadSelection(Stringlist Strings, + Uint16 R1,Uint16 R2,Uint16 A1,Uint16 A2); + + // Code manipulation + bool Jump(Uint16 Address); + bool Call(Uint16 Address); + bool Return(); + + // Variable access + Uint16 GetValue(Uint16 Address); + void SetValue(Uint16 Address,Uint16 Value); + + // Start and stop processing + bool Pause(); + bool Resume(); + + // Eventhandlers + virtual bool EventGameTick(); + virtual bool EventGameProcess(); + virtual void EventSelect(int Selection); + virtual bool EventSave(int Index); + virtual bool EventLoad(int Index); + virtual void EventNew(); + virtual void SetSkipmode(bool Skip); + virtual void SetMessageDelayEnabled(bool Enabled); + virtual void SetMessageDelayInterval(int Interval); +}; + +#endif + From 6341292ea6a1863a5b9b00bebacc5d193eab316f Mon Sep 17 00:00:00 2001 From: monyarm Date: Fri, 15 May 2020 12:51:21 +0300 Subject: [PATCH 2/2] Finished detection.cpp --- base/commandLine.cpp | 435 +++++++++++++++--------------- common/platform.cpp | 1 + common/platform.h | 1 + engines/smt/smt.cpp | 2 +- engines/vileVN/detection.cpp | 148 +--------- engines/vileVN/detection_tables.h | 233 ++++++++++++++++ engines/vileVN/module.mk | 1 + engines/vileVN/vile.cpp | 184 ------------- engines/vileVN/vileVN.cpp | 97 +++++++ engines/vileVN/vileVN.h | 73 +++++ 10 files changed, 634 insertions(+), 541 deletions(-) create mode 100644 engines/vileVN/detection_tables.h create mode 100644 engines/vileVN/vileVN.cpp create mode 100644 engines/vileVN/vileVN.h diff --git a/base/commandLine.cpp b/base/commandLine.cpp index 1c39ec0f78..1c60ed6825 100644 --- a/base/commandLine.cpp +++ b/base/commandLine.cpp @@ -28,10 +28,10 @@ #include #include -#include "engines/metaengine.h" #include "base/commandLine.h" #include "base/plugins.h" #include "base/version.h" +#include "engines/metaengine.h" #include "common/config-manager.h" #include "common/fs.h" @@ -54,49 +54,48 @@ namespace Base { #ifndef DISABLE_COMMAND_LINE static const char USAGE_STRING[] = - "%s: %s\n" - "Usage: %s [OPTIONS]... [GAME]\n" - "\n" - "Try '%s --help' for more options.\n" -; + "%s: %s\n" + "Usage: %s [OPTIONS]... [GAME]\n" + "\n" + "Try '%s --help' for more options.\n"; // DONT FIXME: DO NOT ORDER ALPHABETICALLY, THIS IS ORDERED BY IMPORTANCE/CATEGORY! :) #if defined(__SYMBIAN32__) || defined(ANDROID) || defined(__DS__) || defined(__3DS__) static const char HELP_STRING[] = "NoUsageString"; // save more data segment space #else static const char HELP_STRING[] = - "NovelVM - A 3D game interpreter\n" - "Usage: %s [OPTIONS]... [GAME]\n" - " -v, --version Display NovelVM version information and exit\n" - " -h, --help Display a brief help text and exit\n" - " -z, --list-games Display list of supported games and exit\n" - " -t, --list-targets Display list of configured targets and exit\n" - " --list-engines Display list of suppported engines and exit\n" - " --list-saves Display a list of saved games for the target specified\n" - " with --game=TARGET, or all targets if none is specified\n" - " -a, --add Add all games from current or specified directory.\n" - " If --game=ID is passed only the game with id ID is added. See also --detect\n" - " Use --path=PATH to specify a directory.\n" - " --detect Display a list of games with their ID from current or\n" - " specified directory without adding it to the config.\n" - " Use --path=PATH to specify a directory.\n" - " --game=ID In combination with --add or --detect only adds or attempts to\n" - " detect the game with id ID.\n" - " --auto-detect Display a list of games from current or specified directory\n" - " and start the first one. Use --path=PATH to specify a directory.\n" - " --recursive In combination with --add or --detect recurse down all subdirectories\n" + "NovelVM - A 3D game interpreter\n" + "Usage: %s [OPTIONS]... [GAME]\n" + " -v, --version Display NovelVM version information and exit\n" + " -h, --help Display a brief help text and exit\n" + " -z, --list-games Display list of supported games and exit\n" + " -t, --list-targets Display list of configured targets and exit\n" + " --list-engines Display list of suppported engines and exit\n" + " --list-saves Display a list of saved games for the target specified\n" + " with --game=TARGET, or all targets if none is specified\n" + " -a, --add Add all games from current or specified directory.\n" + " If --game=ID is passed only the game with id ID is added. See also --detect\n" + " Use --path=PATH to specify a directory.\n" + " --detect Display a list of games with their ID from current or\n" + " specified directory without adding it to the config.\n" + " Use --path=PATH to specify a directory.\n" + " --game=ID In combination with --add or --detect only adds or attempts to\n" + " detect the game with id ID.\n" + " --auto-detect Display a list of games from current or specified directory\n" + " and start the first one. Use --path=PATH to specify a directory.\n" + " --recursive In combination with --add or --detect recurse down all subdirectories\n" #if defined(WIN32) && !defined(__SYMBIAN32__) - " --console Enable the console window (default:enabled)\n" + " --console Enable the console window (default:enabled)\n" #endif - "\n" - " -c, --config=CONFIG Use alternate configuration file\n" + "\n" + " -c, --config=CONFIG Use alternate configuration file\n" #if defined(SDL_BACKEND) - " -l, --logfile=PATH Use alternate path for log file\n" + " -l, --logfile=PATH Use alternate path for log file\n" #endif - " -p, --path=PATH Path to where the game is installed\n" - " -x, --save-slot[=NUM] Save game slot to load (default: autosave)\n" - " -f, --fullscreen Force full-screen mode\n" - " -F, --no-fullscreen Force windowed mode\n" + " -p, --path=PATH Path to where the game is installed\n" + " -x, --save-slot[=NUM] Save game slot to load (default: autosave)\n" + " -f, --fullscreen Force full-screen mode\n" + " -F, --no-fullscreen Force windowed mode\n" #if 0 // ResidulVM - not used " -g, --gfx-mode=MODE Select graphics scaler (1x,2x,3x,2xsai,super2xsai,\n" " supereagle,advmame2x,advmame3x,hq2x,hq3x,tv2x,\n" @@ -105,36 +104,36 @@ static const char HELP_STRING[] = " --filtering Force filtered graphics mode\n" " --no-filtering Force unfiltered graphics mode\n" #endif - " --gui-theme=THEME Select GUI theme\n" - " --themepath=PATH Path to where GUI themes are stored\n" - " --list-themes Display list of all usable GUI themes\n" - " -e, --music-driver=MODE Select music driver (see README for details)\n" - " --list-audio-devices List all available audio devices\n" - " -q, --language=LANG Select language (en,de,fr,it,pt,es,jp,zh,kr,se,gb,\n" - " hb,ru,cz)\n" - " -m, --music-volume=NUM Set the music volume, 0-255 (default: 192)\n" - " -s, --sfx-volume=NUM Set the sfx volume, 0-255 (default: 192)\n" - " -r, --speech-volume=NUM Set the speech volume, 0-255 (default: 192)\n" - " --midi-gain=NUM Set the gain for MIDI playback, 0-1000 (default:\n" - " 100) (only supported by some MIDI drivers)\n" - " -n, --subtitles Enable subtitles (use with games that have voice)\n" - " -b, --boot-param=NUM Pass number to the boot script (boot param)\n" - " -d, --debuglevel=NUM Set debug verbosity level\n" - " --debugflags=FLAGS Enable engine specific debug flags\n" - " (separated by commas)\n" - " --debug-channels-only Show only the specified debug channels\n" - " -u, --dump-scripts Enable script dumping if a directory called 'dumps'\n" - " exists in the current directory\n" - "\n" - " --cdrom=DRIVE CD drive to play CD audio from; can either be a\n" - " drive, path, or numeric index (default: 0 = best\n" - " choice drive)\n" - " --joystick[=NUM] Enable joystick input (default: 0 = first joystick)\n" - " --platform=WORD Specify platform of game (allowed values: 2gs, 3do,\n" - " acorn, amiga, atari, c64, fmtowns, nes, mac, pc, pc98,\n" - " pce, segacd, wii, windows)\n" - " --savepath=PATH Path to where saved games are stored\n" - " --extrapath=PATH Extra path to additional game data\n" + " --gui-theme=THEME Select GUI theme\n" + " --themepath=PATH Path to where GUI themes are stored\n" + " --list-themes Display list of all usable GUI themes\n" + " -e, --music-driver=MODE Select music driver (see README for details)\n" + " --list-audio-devices List all available audio devices\n" + " -q, --language=LANG Select language (en,de,fr,it,pt,es,jp,zh,kr,se,gb,\n" + " hb,ru,cz)\n" + " -m, --music-volume=NUM Set the music volume, 0-255 (default: 192)\n" + " -s, --sfx-volume=NUM Set the sfx volume, 0-255 (default: 192)\n" + " -r, --speech-volume=NUM Set the speech volume, 0-255 (default: 192)\n" + " --midi-gain=NUM Set the gain for MIDI playback, 0-1000 (default:\n" + " 100) (only supported by some MIDI drivers)\n" + " -n, --subtitles Enable subtitles (use with games that have voice)\n" + " -b, --boot-param=NUM Pass number to the boot script (boot param)\n" + " -d, --debuglevel=NUM Set debug verbosity level\n" + " --debugflags=FLAGS Enable engine specific debug flags\n" + " (separated by commas)\n" + " --debug-channels-only Show only the specified debug channels\n" + " -u, --dump-scripts Enable script dumping if a directory called 'dumps'\n" + " exists in the current directory\n" + "\n" + " --cdrom=DRIVE CD drive to play CD audio from; can either be a\n" + " drive, path, or numeric index (default: 0 = best\n" + " choice drive)\n" + " --joystick[=NUM] Enable joystick input (default: 0 = first joystick)\n" + " --platform=WORD Specify platform of game (allowed values: 2gs, 3do,\n" + " acorn, amiga, atari, c64, fmtowns, nes, mac, pc, pc98,\n" + " pce, segacd, wii, windows)\n" + " --savepath=PATH Path to where saved games are stored\n" + " --extrapath=PATH Extra path to additional game data\n" #if 0 // ResidulVM - not used " --soundfont=FILE Select the SoundFont for MIDI playback (only\n" " supported by some MIDI drivers)\n" @@ -144,7 +143,7 @@ static const char HELP_STRING[] = " (if file already exists, it will be overwritten)\n" " --enable-gs Enable Roland GS mode for MIDI playback\n" #endif - " --output-rate=RATE Select output sample rate in Hz (e.g. 22050)\n" + " --output-rate=RATE Select output sample rate in Hz (e.g. 22050)\n" #if 0 // ResidulVM - not used " --opl-driver=DRIVER Select AdLib (OPL) emulator (db, mame" #ifndef DISABLE_NUKED_OPL @@ -156,33 +155,33 @@ static const char HELP_STRING[] = ")\n" #endif #if 1 // ResidulVM specific - " --talkspeed=NUM Set talk speed for games (default: 179)\n" - " --show-fps Set the turn on display FPS info\n" - " --no-show-fps Set the turn off display FPS info\n" - " --renderer=RENDERER Select renderer (software, opengl, opengl_shaders)\n" - " --aspect-ratio Enable aspect ratio correction\n" - " --bpp=NUM Select number of bits per pixel, 0 (auto-detect), 16, 32\n" - " (default: 0) (only supported by software renderer)\n" - " --[no-]dirtyrects Enable dirty rectangles optimisation in software renderer\n" - " (default: enabled)\n" + " --talkspeed=NUM Set talk speed for games (default: 179)\n" + " --show-fps Set the turn on display FPS info\n" + " --no-show-fps Set the turn off display FPS info\n" + " --renderer=RENDERER Select renderer (software, opengl, opengl_shaders)\n" + " --aspect-ratio Enable aspect ratio correction\n" + " --bpp=NUM Select number of bits per pixel, 0 (auto-detect), 16, 32\n" + " (default: 0) (only supported by software renderer)\n" + " --[no-]dirtyrects Enable dirty rectangles optimisation in software renderer\n" + " (default: enabled)\n" #endif - " --aspect-ratio Enable aspect ratio correction\n" + " --aspect-ratio Enable aspect ratio correction\n" #if 0 // ResidulVM - not used " --render-mode=MODE Enable additional render modes (hercGreen, hercAmber,\n" " cga, ega, vga, amiga, fmtowns, pc9821, pc9801, 2gs,\n" " atari, macintosh)\n" #endif #ifdef ENABLE_EVENTRECORDER - " --record-mode=MODE Specify record mode for event recorder (record, playback,\n" - " passthrough [default])\n" - " --record-file-name=FILE Specify record file name\n" - " --disable-display Disable any gfx output. Used for headless events\n" - " playback by Event Recorder\n" + " --record-mode=MODE Specify record mode for event recorder (record, playback,\n" + " passthrough [default])\n" + " --record-file-name=FILE Specify record file name\n" + " --disable-display Disable any gfx output. Used for headless events\n" + " playback by Event Recorder\n" #endif - "\n" + "\n" #if defined(ENABLE_SKY) || defined(ENABLE_QUEEN) - " --alt-intro Use alternative intro for CD versions of Beneath a\n" - " Steel Sky and Flight of the Amazon Queen\n" + " --alt-intro Use alternative intro for CD versions of Beneath a\n" + " Steel Sky and Flight of the Amazon Queen\n" #endif #if 0 // ResidulVM - not used " --copy-protection Enable copy protection in games, when\n" @@ -190,28 +189,27 @@ static const char HELP_STRING[] = " --talkspeed=NUM Set talk speed for games (default: 60)\n" #endif #if defined(ENABLE_SCUMM) || defined(ENABLE_GROOVIE) - " --demo-mode Start demo mode of Maniac Mansion or The 7th Guest\n" + " --demo-mode Start demo mode of Maniac Mansion or The 7th Guest\n" #endif #if defined(ENABLE_DIRECTOR) - " --start-movie=NAME Start movie for Director\n" + " --start-movie=NAME Start movie for Director\n" #endif -//#ifdef ENABLE_SCUMM // NovelVM not used - " --tempo=NUM Set music tempo (in percent, 50-200) for SCUMM games\n" - " (default: 100)\n" + //#ifdef ENABLE_SCUMM // NovelVM not used + " --tempo=NUM Set music tempo (in percent, 50-200) for SCUMM games\n" + " (default: 100)\n" //#ifdef ENABLE_SCUMM_7_8 // NovelVM not used #ifdef ENABLE_GRIM // NovelVM specific - " --dimuse-tempo=NUM Set internal Digital iMuse tempo (10 - 100) per second\n" - " (default: 10)\n" + " --dimuse-tempo=NUM Set internal Digital iMuse tempo (10 - 100) per second\n" + " (default: 10)\n" #endif //#endif // NovelVM - not used #if 1 // ResidulVM specific - " --engine-speed=NUM Set frame per second limit (0 - 100), 0 = no limit\n" - " (default: 60)\n" + " --engine-speed=NUM Set frame per second limit (0 - 100), 0 = no limit\n" + " (default: 60)\n" #endif - "\n" - "The meaning of boolean long options can be inverted by prefixing them with\n" - "\"no-\", e.g. \"--no-aspect-ratio\".\n" -; + "\n" + "The meaning of boolean long options can be inverted by prefixing them with\n" + "\"no-\", e.g. \"--no-aspect-ratio\".\n"; #endif static const char *s_appName = "novelvm"; @@ -243,7 +241,6 @@ static Common::String buildQualifiedGameName(const Common::String &engineId, con #endif // DISABLE_COMMAND_LINE - void registerDefaults() { // Graphics @@ -251,17 +248,17 @@ void registerDefaults() { ConfMan.registerDefault("filtering", false); ConfMan.registerDefault("show_fps", false); ConfMan.registerDefault("aspect_ratio", false); -/* NovelVM - not used + /* NovelVM - not used ConfMan.registerDefault("gfx_mode", "normal"); ConfMan.registerDefault("render_mode", "default"); ConfMan.registerDefault("desired_screen_aspect_ratio", "auto"); ConfMan.registerDefault("stretch_mode", "default"); ConfMan.registerDefault("shader", "default");*/ -// NovelVM specific start + // NovelVM specific start ConfMan.registerDefault("show_fps", false); ConfMan.registerDefault("dirtyrects", true); ConfMan.registerDefault("bpp", 0); -// NovelVM specific end + // NovelVM specific end // Sound & Music ConfMan.registerDefault("music_volume", 192); @@ -275,7 +272,7 @@ void registerDefaults() { ConfMan.registerDefault("multi_midi", false); ConfMan.registerDefault("native_mt32", false); -/* NovelVM - not used + /* NovelVM - not used ConfMan.registerDefault("dump_midi", false); ConfMan.registerDefault("enable_gs", false); ConfMan.registerDefault("midi_gain", 100); @@ -303,7 +300,7 @@ void registerDefaults() { ConfMan.registerDefault("object_labels", true); #endif -/* NovelVM - not used + /* NovelVM - not used ConfMan.registerDefault("copy_protection", false); ConfMan.registerDefault("talkspeed", 60);*/ @@ -435,76 +432,82 @@ static Common::String createTemporaryTarget(const Common::String &engineId, cons #ifndef DISABLE_COMMAND_LINE // Use this for options which have an *optional* value -#define DO_OPTION_OPT(shortCmd, longCmd, defaultVal) \ - if (isLongCmd ? (!strcmp(s + 2, longCmd) || !memcmp(s + 2, longCmd"=", sizeof(longCmd"=") - 1)) : (tolower(s[1]) == shortCmd)) { \ - s += 2; \ - if (isLongCmd) { \ - s += sizeof(longCmd) - 1; \ - if (*s == '=') \ - s++; \ - } \ - const char *option = s; \ - if (*s == '\0' && !isLongCmd) { option = s2; i++; } \ - if (!option || *option == '\0') option = defaultVal; \ - if (option) settings[longCmd] = option; +#define DO_OPTION_OPT(shortCmd, longCmd, defaultVal) \ + if (isLongCmd ? (!strcmp(s + 2, longCmd) || !memcmp(s + 2, longCmd "=", sizeof(longCmd "=") - 1)) : (tolower(s[1]) == shortCmd)) { \ + s += 2; \ + if (isLongCmd) { \ + s += sizeof(longCmd) - 1; \ + if (*s == '=') \ + s++; \ + } \ + const char *option = s; \ + if (*s == '\0' && !isLongCmd) { \ + option = s2; \ + i++; \ + } \ + if (!option || *option == '\0') \ + option = defaultVal; \ + if (option) \ + settings[longCmd] = option; // Use this for options which have a required (string) value -#define DO_OPTION(shortCmd, longCmd) \ +#define DO_OPTION(shortCmd, longCmd) \ DO_OPTION_OPT(shortCmd, longCmd, 0) \ - if (!option) usage("Option '%s' requires an argument", argv[isLongCmd ? i : i-1]); + if (!option) \ + usage("Option '%s' requires an argument", argv[isLongCmd ? i : i - 1]); // Use this for options which have a required integer value // (we don't check ERANGE because WinCE doesn't support errno, so we're stuck just rejecting LONG_MAX/LONG_MIN..) -#define DO_OPTION_INT(shortCmd, longCmd) \ - DO_OPTION(shortCmd, longCmd) \ - char *endptr; \ - long int retval = strtol(option, &endptr, 0); \ +#define DO_OPTION_INT(shortCmd, longCmd) \ + DO_OPTION(shortCmd, longCmd) \ + char *endptr; \ + long int retval = strtol(option, &endptr, 0); \ if (*endptr != '\0' || retval == LONG_MAX || retval == LONG_MIN) \ usage("--%s: Invalid number '%s'", longCmd, option); // Use this for boolean options; this distinguishes between "-x" and "-X", // resp. between "--some-option" and "--no-some-option". -#define DO_OPTION_BOOL(shortCmd, longCmd) \ +#define DO_OPTION_BOOL(shortCmd, longCmd) \ if (isLongCmd ? (!strcmp(s + 2, longCmd) || !strcmp(s + 2, "no-" longCmd)) : (tolower(s[1]) == shortCmd)) { \ - bool boolValue = (Common::isLower(s[1]) != 0); \ - s += 2; \ - if (isLongCmd) { \ - boolValue = !strcmp(s, longCmd); \ - s += boolValue ? (sizeof(longCmd) - 1) : (sizeof("no-" longCmd) - 1); \ - } \ - if (*s != '\0') goto unknownOption; \ - const char *option = boolValue ? "true" : "false"; \ + bool boolValue = (Common::isLower(s[1]) != 0); \ + s += 2; \ + if (isLongCmd) { \ + boolValue = !strcmp(s, longCmd); \ + s += boolValue ? (sizeof(longCmd) - 1) : (sizeof("no-" longCmd) - 1); \ + } \ + if (*s != '\0') \ + goto unknownOption; \ + const char *option = boolValue ? "true" : "false"; \ settings[longCmd] = option; // Use this for options which never have a value, i.e. for 'commands', like "--help". -#define DO_COMMAND(shortCmd, longCmd) \ +#define DO_COMMAND(shortCmd, longCmd) \ if (isLongCmd ? (!strcmp(s + 2, longCmd)) : (tolower(s[1]) == shortCmd)) { \ - s += 2; \ - if (isLongCmd) \ - s += sizeof(longCmd) - 1; \ - if (*s != '\0') goto unknownOption; \ - ensureFirstCommand(command, longCmd); \ + s += 2; \ + if (isLongCmd) \ + s += sizeof(longCmd) - 1; \ + if (*s != '\0') \ + goto unknownOption; \ + ensureFirstCommand(command, longCmd); \ command = longCmd; - -#define DO_LONG_OPTION_OPT(longCmd, d) DO_OPTION_OPT(0, longCmd, d) -#define DO_LONG_OPTION(longCmd) DO_OPTION(0, longCmd) -#define DO_LONG_OPTION_INT(longCmd) DO_OPTION_INT(0, longCmd) -#define DO_LONG_OPTION_BOOL(longCmd) DO_OPTION_BOOL(0, longCmd) -#define DO_LONG_COMMAND(longCmd) DO_COMMAND(0, longCmd) +#define DO_LONG_OPTION_OPT(longCmd, d) DO_OPTION_OPT(0, longCmd, d) +#define DO_LONG_OPTION(longCmd) DO_OPTION(0, longCmd) +#define DO_LONG_OPTION_INT(longCmd) DO_OPTION_INT(0, longCmd) +#define DO_LONG_OPTION_BOOL(longCmd) DO_OPTION_BOOL(0, longCmd) +#define DO_LONG_COMMAND(longCmd) DO_COMMAND(0, longCmd) // End an option handler #define END_OPTION \ - continue; \ + continue; \ } // End an option handler #define END_COMMAND \ - continue; \ + continue; \ } - -Common::String parseCommandLine(Common::StringMap &settings, int argc, const char * const *argv) { +Common::String parseCommandLine(Common::StringMap &settings, int argc, const char *const *argv) { const char *s, *s2; Common::String command; @@ -522,7 +525,7 @@ Common::String parseCommandLine(Common::StringMap &settings, int argc, const cha // Iterate over all command line arguments and parse them into our string map. for (int i = 1; i < argc; ++i) { s = argv[i]; - s2 = (i < argc-1) ? argv[i+1] : 0; + s2 = (i < argc - 1) ? argv[i + 1] : 0; if (s[0] != '-') { // The argument doesn't start with a dash, so it's not an option. @@ -637,7 +640,7 @@ Common::String parseCommandLine(Common::StringMap &settings, int argc, const cha DO_LONG_OPTION("opl-driver") END_OPTION -/* NovelVM - not used + /* NovelVM - not used DO_OPTION('g', "gfx-mode") END_OPTION @@ -654,17 +657,17 @@ Common::String parseCommandLine(Common::StringMap &settings, int argc, const cha END_OPTION DO_OPTION('p', "path") - Common::FSNode path(option); - if (!path.exists()) { - usage("Non-existent game path '%s'", option); - } else if (!path.isReadable()) { - usage("Non-readable game path '%s'", option); - } + Common::FSNode path(option); + if (!path.exists()) { + usage("Non-existent game path '%s'", option); + } else if (!path.isReadable()) { + usage("Non-readable game path '%s'", option); + } END_OPTION DO_OPTION('q', "language") - if (Common::parseLanguage(option) == Common::UNK_LANG) - usage("Unrecognized language '%s'", option); + if (Common::parseLanguage(option) == Common::UNK_LANG) + usage("Unrecognized language '%s'", option); END_OPTION DO_OPTION_INT('s', "sfx-volume") @@ -686,23 +689,23 @@ Common::String parseCommandLine(Common::StringMap &settings, int argc, const cha END_OPTION DO_LONG_OPTION_OPT("joystick", "0") - settings["joystick_num"] = option; - settings.erase("joystick"); + settings["joystick_num"] = option; + settings.erase("joystick"); END_OPTION DO_LONG_OPTION("platform") - int platform = Common::parsePlatform(option); - if (platform == Common::kPlatformUnknown) - usage("Unrecognized platform '%s'", option); + int platform = Common::parsePlatform(option); + if (platform == Common::kPlatformUnknown) + usage("Unrecognized platform '%s'", option); END_OPTION DO_LONG_OPTION("soundfont") - Common::FSNode path(option); - if (!path.exists()) { - usage("Non-existent soundfont path '%s'", option); - } else if (!path.isReadable()) { - usage("Non-readable soundfont path '%s'", option); - } + Common::FSNode path(option); + if (!path.exists()) { + usage("Non-existent soundfont path '%s'", option); + } else if (!path.isReadable()) { + usage("Non-readable soundfont path '%s'", option); + } END_OPTION DO_LONG_OPTION_BOOL("disable-sdl-parachute") @@ -714,7 +717,7 @@ Common::String parseCommandLine(Common::StringMap &settings, int argc, const cha DO_LONG_OPTION_BOOL("native-mt32") END_OPTION -/* NovelVM - not used + /* NovelVM - not used DO_LONG_OPTION_BOOL("dump-midi") END_OPTION*/ @@ -724,13 +727,13 @@ Common::String parseCommandLine(Common::StringMap &settings, int argc, const cha DO_LONG_OPTION_BOOL("aspect-ratio") END_OPTION -/* NovelVM - not used + /* NovelVM - not used DO_LONG_OPTION("render-mode") int renderMode = Common::parseRenderMode(option); if (renderMode == Common::kRenderDefault) usage("Unrecognized render mode '%s'", option);*/ -// NovelVM specific start + // NovelVM specific start DO_LONG_OPTION_INT("bpp") END_OPTION @@ -739,39 +742,39 @@ Common::String parseCommandLine(Common::StringMap &settings, int argc, const cha DO_LONG_OPTION("gamma") END_OPTION -// NovelVM specific start + // NovelVM specific start DO_LONG_OPTION("renderer") - Graphics::RendererType renderer = Graphics::parseRendererTypeCode(option); - if (renderer == Graphics::kRendererTypeDefault) - usage("Unrecognized renderer type '%s'", option); + Graphics::RendererType renderer = Graphics::parseRendererTypeCode(option); + if (renderer == Graphics::kRendererTypeDefault) + usage("Unrecognized renderer type '%s'", option); END_OPTION DO_LONG_OPTION_BOOL("show-fps") -// NovelVM specific end + // NovelVM specific end END_OPTION DO_LONG_OPTION("savepath") - Common::FSNode path(option); - if (!path.exists()) { - usage("Non-existent saved games path '%s'", option); - } else if (!path.isWritable()) { - usage("Non-writable saved games path '%s'", option); - } + Common::FSNode path(option); + if (!path.exists()) { + usage("Non-existent saved games path '%s'", option); + } else if (!path.isWritable()) { + usage("Non-writable saved games path '%s'", option); + } END_OPTION DO_LONG_OPTION("extrapath") - Common::FSNode path(option); - if (!path.exists()) { - usage("Non-existent extra path '%s'", option); - } else if (!path.isReadable()) { - usage("Non-readable extra path '%s'", option); - } + Common::FSNode path(option); + if (!path.exists()) { + usage("Non-existent extra path '%s'", option); + } else if (!path.isReadable()) { + usage("Non-readable extra path '%s'", option); + } END_OPTION DO_LONG_OPTION_INT("talkspeed") END_OPTION -/* NovelVM - not used + /* NovelVM - not used DO_LONG_OPTION_BOOL("copy-protection") END_OPTION*/ @@ -785,12 +788,12 @@ Common::String parseCommandLine(Common::StringMap &settings, int argc, const cha END_OPTION DO_LONG_OPTION("themepath") - Common::FSNode path(option); - if (!path.exists()) { - usage("Non-existent theme path '%s'", option); - } else if (!path.isReadable()) { - usage("Non-readable theme path '%s'", option); - } + Common::FSNode path(option); + if (!path.exists()) { + usage("Non-existent theme path '%s'", option); + } else if (!path.isReadable()) { + usage("Non-readable theme path '%s'", option); + } END_OPTION DO_LONG_COMMAND("list-themes") @@ -817,7 +820,6 @@ Common::String parseCommandLine(Common::StringMap &settings, int argc, const cha END_OPTION #endif - // NovelVM specific start #ifdef ENABLE_GRIM DO_LONG_OPTION_INT("dimuse-tempo") @@ -825,7 +827,7 @@ Common::String parseCommandLine(Common::StringMap &settings, int argc, const cha #endif DO_LONG_OPTION_INT("engine-speed") END_OPTION -// NovelVM specific end + // NovelVM specific end #ifdef IPHONE // This is automatically set when launched from the Springboard. @@ -844,7 +846,7 @@ Common::String parseCommandLine(Common::StringMap &settings, int argc, const cha END_OPTION #endif -unknownOption: + unknownOption: // If we get till here, the option is unhandled and hence unknown. usage("Unrecognized option '%s'", argv[i]); } @@ -855,10 +857,17 @@ Common::String parseCommandLine(Common::StringMap &settings, int argc, const cha /** List all supported game IDs, i.e. all games which any loaded plugin supports. */ static void listGames() { + const PluginList &plugins = EngineMan.getPlugins(); + int gameCount = 0; + for (PluginList::const_iterator iter = plugins.begin(); iter != plugins.end(); ++iter) { + const MetaEngine &metaengine = (*iter)->get(); + gameCount += metaengine.getSupportedGames().size(); + } + + printf("%i Games Supported\n", gameCount); printf("Game ID Full Title State URL \n" "------------------------------ ------------------------------------------------------------ ----------------------------- ------------------------------------------------------------\n"); - const PluginList &plugins = EngineMan.getPlugins(); for (PluginList::const_iterator iter = plugins.begin(); iter != plugins.end(); ++iter) { const MetaEngine &metaengine = (*iter)->get(); @@ -990,7 +999,7 @@ static Common::Error listSaves(const Common::String &singleTarget) { printf("\n"); printf("Save states for target '%s' (gameid '%s'):\n", i->c_str(), qualifiedGameId.c_str()); printf(" Slot Description \n" - " ---- ------------------------------------------------------\n"); + " ---- ------------------------------------------------------\n"); for (SaveStateList::const_iterator x = saveList.begin(); x != saveList.end(); ++x) { printf(" %-4d %s\n", x->getSaveSlot(), x->getDescription().c_str()); @@ -1072,8 +1081,7 @@ static DetectedGames recListGames(const Common::FSNode &dir, const Common::Strin for (Common::FSList::const_iterator file = files.begin(); file != files.end(); ++file) { DetectedGames rec = recListGames(*file, engineId, gameId, recursive); for (DetectedGames::const_iterator game = rec.begin(); game != rec.end(); ++game) { - if ((game->engineId == engineId && game->gameId == gameId) - || gameId.empty()) + if ((game->engineId == engineId && game->gameId == gameId) || gameId.empty()) list.push_back(*game); } } @@ -1116,8 +1124,7 @@ static int recAddGames(const Common::FSNode &dir, const Common::String &engineId int count = 0; DetectedGames list = getGameList(dir); for (DetectedGames::const_iterator v = list.begin(); v != list.end(); ++v) { - if ((v->engineId != engineId || v->gameId != gameId) - && !gameId.empty()) { + if ((v->engineId != engineId || v->gameId != gameId) && !gameId.empty()) { printf("Found %s, only adding %s per --game option, ignoring...\n", buildQualifiedGameName(v->engineId, v->gameId).c_str(), buildQualifiedGameName(engineId, gameId).c_str()); @@ -1135,8 +1142,7 @@ static int recAddGames(const Common::FSNode &dir, const Common::String &engineId buildQualifiedGameName(v->engineId, v->gameId).c_str(), v->description.c_str(), Common::getLanguageDescription(v->language), - Common::getPlatformDescription(v->platform) - ); + Common::getPlatformDescription(v->platform)); } } @@ -1179,7 +1185,7 @@ static void runDetectorTest() { Common::String gameid(iter->_value.getVal("gameid")); Common::String path(iter->_value.getVal("path")); printf("Looking at target '%s', gameid '%s', path '%s' ...\n", - name.c_str(), gameid.c_str(), path.c_str()); + name.c_str(), gameid.c_str(), path.c_str()); if (path.empty()) { printf(" ... no path specified, skipping\n"); continue; @@ -1224,15 +1230,15 @@ static void runDetectorTest() { for (x = candidates.begin(); x != candidates.end(); ++x) { printf(" gameid '%s', desc '%s', language '%s', platform '%s'\n", - x->gameId.c_str(), - x->description.c_str(), - Common::getLanguageDescription(x->language), - Common::getPlatformDescription(x->platform)); + x->gameId.c_str(), + x->description.c_str(), + Common::getLanguageDescription(x->language), + Common::getPlatformDescription(x->platform)); } } int total = domains.size(); printf("Detector test run: %d fail, %d success, %d skipped, out of %d\n", - failure, success, total - failure - success, total); + failure, success, total - failure - success, total); } #endif @@ -1254,7 +1260,7 @@ void upgradeTargets() { Common::String gameid(dom.getVal("gameid")); Common::String path(dom.getVal("path")); printf("Looking at target '%s', gameid '%s' ...\n", - name.c_str(), gameid.c_str()); + name.c_str(), gameid.c_str()); if (path.empty()) { printf(" ... no path specified, skipping\n"); continue; @@ -1355,15 +1361,12 @@ void upgradeTargets() { #else // DISABLE_COMMAND_LINE - -Common::String parseCommandLine(Common::StringMap &settings, int argc, const char * const *argv) { +Common::String parseCommandLine(Common::StringMap &settings, int argc, const char *const *argv) { return Common::String(); } - #endif // DISABLE_COMMAND_LINE - bool processSettings(Common::String &command, Common::StringMap &settings, Common::Error &err) { err = Common::kNoError; @@ -1447,7 +1450,6 @@ bool processSettings(Common::String &command, Common::StringMap &settings, Commo #endif // DISABLE_COMMAND_LINE - // If a target was specified, check whether there is either a game // domain (i.e. a target) matching this argument, or alternatively // whether there is a gameid matching that name. @@ -1467,7 +1469,6 @@ bool processSettings(Common::String &command, Common::StringMap &settings, Commo } } - // Finally, store the command line settings into the config manager. for (Common::StringMap::const_iterator x = settings.begin(); x != settings.end(); ++x) { Common::String key(x->_key); diff --git a/common/platform.cpp b/common/platform.cpp index 766d68eaf5..c17f4f4af6 100644 --- a/common/platform.cpp +++ b/common/platform.cpp @@ -63,6 +63,7 @@ const PlatformDescription g_platforms[] = { { "psv", "psv", "psv", "Sony Playstation Vita", kPlatformPSVita }, { "ps3", "ps3", "ps3", "Sony Playstation 3", kPlatformPS3 }, { "ps4", "ps4", "ps4", "Sony Playstation 4", kPlatformPS4 }, + { "dc", "dc", "dc", "Sega Dreamcast", kPlatformDreamcast }, { nullptr, nullptr, nullptr, "Default", kPlatformUnknown } }; diff --git a/common/platform.h b/common/platform.h index 1f6b17cfaa..8ecd5dcb46 100644 --- a/common/platform.h +++ b/common/platform.h @@ -67,6 +67,7 @@ enum Platform { kPlatformPSVita, kPlatformPS3, kPlatformPS4, + kPlatformDreamcast, kPlatformUnknown = -1 }; diff --git a/engines/smt/smt.cpp b/engines/smt/smt.cpp index 6f9dafe96f..054f96dd13 100644 --- a/engines/smt/smt.cpp +++ b/engines/smt/smt.cpp @@ -120,7 +120,7 @@ namespace SMT while (!shouldQuit()) { g_system->getEventManager()->pollEvent(e); - g_system->delayMillis(10); + g_system->delayMillis(1); } return Common::kNoError; diff --git a/engines/vileVN/detection.cpp b/engines/vileVN/detection.cpp index b65aea0036..44d0c69d5e 100644 --- a/engines/vileVN/detection.cpp +++ b/engines/vileVN/detection.cpp @@ -1,20 +1,6 @@ -//#include "vileVN/vile.h" +#include "vileVN/vileVN.h" -#include "base/plugins.h" - -#include "engines/advancedDetector.h" - -#define PROBESUF(name, platform) PROBESUFFULL(name, name,platform, Common::EN_ANY), \ - PROBESUFFULL(name, name,platform, Common::JA_JPN), \ - PROBESUFFULL(name, name,platform, Common::RU_RUS) - -#define PROBESUFFULL(name, name2, platform, lang) \ - {name, 0, AD_ENTRY1s("game.suf", NULL, -1), lang, platform, ADGF_NO_FLAGS, GUIO1(GUIO_NONE)}, \ - {name, 0, AD_ENTRY1s("us.suf", NULL, -1), lang, platform, ADGF_NO_FLAGS, GUIO1(GUIO_NONE)}, \ - {name, 0, AD_ENTRY1s("ml.suf", NULL, -1), lang, platform, ADGF_NO_FLAGS, GUIO1(GUIO_NONE)}, \ - {name, 0, AD_ENTRY1s(name2 ".suf", NULL, -1), lang, platform, ADGF_NO_FLAGS, GUIO1(GUIO_NONE)}, \ - {name, 0, AD_ENTRY1s(name2 "us.suf", NULL, -1), lang, platform, ADGF_NO_FLAGS, GUIO1(GUIO_NONE)}, \ - { name, 0, AD_ENTRY1s(name2 "ml.suf", NULL, -1), lang, platform, ADGF_NO_FLAGS, GUIO1(GUIO_NONE) } +#include "detection_tables.h" namespace VileVN { //const char *VileVNEngine::getGameId() const { return _gameDescription->gameId; } @@ -22,127 +8,6 @@ namespace VileVN { } // namespace VileVN -static const PlainGameDescriptor VileVNGames[] = { - {"mayclub", "May Club", "WIP", "https://vndb.org/v190"}, - {"mayclub2", "May Club 2", "WIP", "https://vndb.org/v190"}, - {"nocIll", "Nocturnal Illusion", "WIP", "https://vndb.org/v190"}, - {"cres", "Crescendo ~Eien da to Omotte Ita Ano Koro~", "WIP", "https://vndb.org/v29"}, - {"sagara", "Sagara-sanchi no Etsuraku Life", "WIP", "https://vndb.org/v46"}, - {"yuki", "Yuki Sakura", "WIP", "https://vndb.org/v71"}, - {"kanaoka", "Kana ~Imouto~", "WIP", "https://vndb.org/v2"}, - {"hitomi", "Gimai - Hitomi", "WIP", "https://vndb.org/v31"}, - {"koneko", "Koneko Doumei", "WIP", "https://vndb.org/v153"}, - {"mesia", "Meshimase Idol", "WIP", "https://vndb.org/v141"}, - {0, 0, 0, 0}}; - -namespace VileVN { - -static const ADGameDescription gameDescriptions[] = { - //May Club 1 - {"mayclub", - 0, - {{"may0.dat", 0, NULL, -1}, - {"may0.lst", 0, NULL, -1}, - {"cg/graphics.pak", 0, NULL, -1}, - {"wave/n02_88.wav", 0, NULL, -1}, - AD_LISTEND}, - Common::EN_ANY, - Common::kPlatformWindows, - ADGF_NO_FLAGS, - GUIO1(GUIO_NONE)}, - {"mayclub", - 0, - {{"may0.dat", 0, NULL, -1}, - {"may0.lst", 0, NULL, -1}, - {"cg/graphics.pak", 0, NULL, -1}, - {"wave/n02_88.wav", 0, NULL, -1}, - AD_LISTEND}, - Common::EN_ANY, - Common::kPlatformPC98, - ADGF_NO_FLAGS, - GUIO1(GUIO_NONE)}, - {"mayclub", - 0, - {{"may0.dat", 0, NULL, -1}, - {"may0.lst", 0, NULL, -1}, - {"cg/graphics.pak", 0, NULL, -1}, - {"wave/n02_88.wav", 0, NULL, -1}, - AD_LISTEND}, - Common::EN_ANY, - Common::kPlatformMacintosh, - ADGF_NO_FLAGS, - GUIO1(GUIO_NONE)}, - {"mayclub", - 0, - {{"may0.dat", 0, NULL, -1}, - {"may0.lst", 0, NULL, -1}, - {"cg/graphics.pak", 0, NULL, -1}, - {"wave/n02_88.wav", 0, NULL, -1}, - AD_LISTEND}, - Common::EN_ANY, - Common::kPlatformLinux, - ADGF_NO_FLAGS, - GUIO1(GUIO_NONE)}, - - //May Club 2 - {"mayclub2", - 0, - {{"may0.dat", 0, NULL, -1}, - {"may0.lst", 0, NULL, -1}, - {"cg/graphics.pak", 0, NULL, -1}, - {"wave/n02_88.wav", 0, NULL, -1}, - AD_LISTEND}, - Common::EN_ANY, - Common::kPlatformWindows, - ADGF_NO_FLAGS, - GUIO1(GUIO_NONE)}, - - //Nocturnal Illusion - {"nocIll", - 0, - {{"mug0.dat", 0, NULL, -1}, - {"mug0.lst", 0, NULL, -1}, - AD_LISTEND}, - Common::EN_ANY, - Common::kPlatformWindows, - ADGF_NO_FLAGS, - GUIO1(GUIO_NONE)}, - - //Crescendo - PROBESUF("cres", Common::kPlatformWindows), - PROBESUF("cres", Common::kPlatformMacintosh), - PROBESUF("cres", Common::kPlatformLinux), - - //Sagara - PROBESUF("sagara", Common::kPlatformWindows), - - //Yuki Sakura - PROBESUF("yuki", Common::kPlatformWindows), - - //Kanao Okaeri - PROBESUF("kanaoka", Common::kPlatformWindows), - PROBESUF("kanaoka", Common::kPlatformMacintosh), - PROBESUF("kanaoka", Common::kPlatformLinux), - PROBESUF("kanaoka", Common::kPlatformPSP), - - PROBESUFFULL("kanaoka", "kana", Common::kPlatformWindows,Common::EN_ANY), - PROBESUFFULL("kanaoka", "kana", Common::kPlatformMacintosh,Common::EN_ANY), - PROBESUFFULL("kanaoka", "kana", Common::kPlatformLinux,Common::EN_ANY), - PROBESUFFULL("kanaoka", "kana", Common::kPlatformPSP,Common::EN_ANY), - - //Hitomi - PROBESUF("hitomi", Common::kPlatformWindows), - - //Cat Girl Alliance - PROBESUF("koneko", Common::kPlatformWindows), - - //Idols Galore - PROBESUF("mesia", Common::kPlatformWindows), - - AD_TABLE_END_MARKER}; - -} // End of namespace VileVN - class VileVNMetaEngine : public AdvancedMetaEngine { public: VileVNMetaEngine() : AdvancedMetaEngine(VileVN::gameDescriptions, sizeof(ADGameDescription), VileVNGames) { @@ -169,10 +34,15 @@ bool VileVNMetaEngine::hasFeature(MetaEngineFeature f) const { } bool VileVNMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const { + + if(strcmp(desc->filesDescriptions->fileName, "frames.pck")){ + //*engine - new VileVN::JASTUSAEngine(syst,desc); + } + if (desc) - ///*engine = new VileVN::VileVNEngine(syst, desc); + *engine = new VileVN::VileVNEngine(syst, desc); - return desc != nullptr; + return desc != nullptr; } #if PLUGIN_ENABLED_DYNAMIC(VILEVN) diff --git a/engines/vileVN/detection_tables.h b/engines/vileVN/detection_tables.h new file mode 100644 index 0000000000..b205796551 --- /dev/null +++ b/engines/vileVN/detection_tables.h @@ -0,0 +1,233 @@ + +#include "base/plugins.h" + +#include "engines/advancedDetector.h" + +#define PROBESUF(name, platform) PROBESUFFULL(name, name, platform, Common::EN_ANY), \ + PROBESUFFULL(name, name, platform, Common::JA_JPN), \ + PROBESUFFULL(name, name, platform, Common::RU_RUS) + +#define PROBESUFFULL(name, name2, platform, lang) \ + {name, 0, AD_ENTRY1s("game.suf", NULL, -1), lang, platform, ADGF_NO_FLAGS, GUIO1(GUIO_NONE)}, \ + {name, 0, AD_ENTRY1s("us.suf", NULL, -1), lang, platform, ADGF_NO_FLAGS, GUIO1(GUIO_NONE)}, \ + {name, 0, AD_ENTRY1s("ml.suf", NULL, -1), lang, platform, ADGF_NO_FLAGS, GUIO1(GUIO_NONE)}, \ + {name, 0, AD_ENTRY1s(name2 ".suf", NULL, -1), lang, platform, ADGF_NO_FLAGS, GUIO1(GUIO_NONE)}, \ + {name, 0, AD_ENTRY1s(name2 "us.suf", NULL, -1), lang, platform, ADGF_NO_FLAGS, GUIO1(GUIO_NONE)}, \ + { name, 0, AD_ENTRY1s(name2 "ml.suf", NULL, -1), lang, platform, ADGF_NO_FLAGS, GUIO1(GUIO_NONE) } + +#define PROBEJASTUSANAME(name) PROBEJASTUSAFULL(name, Common::kPlatformWindows, Common::EN_ANY) + +#define PROBEJASTUSAFULL(name, platform, lang) \ + {name, 0, {{"frames.pck", 0, NULL, -1},{"data.pck", 0, NULL, -1}, {"images.pck", 0, NULL, -1}, AD_LISTEND}, lang, platform, ADGF_NO_FLAGS, GUIO1(GUIO_NONE)} + +#define PROBEJASTUSA() \ + PROBEJASTUSANAME("meisou"), \ + PROBEJASTUSANAME("sakura"), \ + PROBEJASTUSANAME("sanshi") + +#define PROBEDIVIDEADPLATLANG(platform, lang) \ + { "dividead", 0, {{"sg.dl1", 0, NULL, -1}, {"wv.dl1", 0, NULL, -1}, AD_LISTEND}, \ + lang, \ + platform, \ + ADGF_NO_FLAGS, \ + GUIO1(GUIO_NONE) } + +#define PROBEDIVIDEADPLAT(platform) \ + PROBEDIVIDEADPLATLANG(platform, Common::EN_ANY), \ + PROBEDIVIDEADPLATLANG(platform, Common::PT_BRA), \ + PROBEDIVIDEADPLATLANG(platform, Common::PT_POR), \ + PROBEDIVIDEADPLATLANG(platform, Common::JA_JPN), \ + PROBEDIVIDEADPLATLANG(platform, Common::ES_ESP) + +#define PROBEDIVIDEAD() \ + PROBEDIVIDEADPLAT(Common::kPlatformWindows), \ + PROBEDIVIDEADPLAT(Common::kPlatformPSP), \ + PROBEDIVIDEADPLAT(Common::kPlatformXbox), \ + PROBEDIVIDEADPLAT(Common::kPlatformDreamcast) + +#define PROBEKANAOKA() \ + PROBESUF("kanaoka", Common::kPlatformWindows), \ + PROBESUF("kanaoka", Common::kPlatformMacintosh), \ + PROBESUF("kanaoka", Common::kPlatformLinux), \ + PROBESUF("kanaoka", Common::kPlatformPSP), \ + PROBESUFFULL("kanaoka", "kana", Common::kPlatformWindows, Common::EN_ANY), \ + PROBESUFFULL("kanaoka", "kana", Common::kPlatformMacintosh, Common::EN_ANY), \ + PROBESUFFULL("kanaoka", "kana", Common::kPlatformLinux, Common::EN_ANY), \ + PROBESUFFULL("kanaoka", "kana", Common::kPlatformPSP, Common::EN_ANY) + +#define PROBEMAYCLUBFULL(platform, lang) \ + { "mayclub", 0, {{"may0.dat", 0, NULL, -1}, {"may0.lst", 0, NULL, -1}, {"cg/graphics.pak", 0, NULL, -1}, {"wave/n02_88.wav", 0, NULL, -1}, AD_LISTEND}, lang, platform, ADGF_NO_FLAGS, GUIO1(GUIO_NONE) } +#define PROBEMAYCLUB2FULL(platform, lang) \ + { "mayclub", 0, {{"may0.dat", 0, NULL, -1}, {"may0.lst", 0, NULL, -1}, {"cg/graphics.pak", 0, NULL, -1}, {"wave/n02_88.wav", 0, NULL, -1}, AD_LISTEND}, lang, platform, ADGF_NO_FLAGS, GUIO1(GUIO_NONE) } +#define PROBEMAYCLUBLANG(lang) \ + PROBEMAYCLUBFULL(Common::kPlatformWindows, lang), \ + PROBEMAYCLUB2FULL(Common::kPlatformWindows, lang), \ + PROBEMAYCLUBFULL(Common::kPlatformLinux, lang), \ + PROBEMAYCLUBFULL(Common::kPlatformPC98, lang), \ + PROBEMAYCLUBFULL(Common::kPlatformMacintosh, lang) + +#define PROBEMAYCLUB() \ + PROBEMAYCLUBLANG(Common::EN_ANY), \ + PROBEMAYCLUBLANG(Common::JA_JPN), \ + PROBEJASTUSANAME("mayclub") + +#define PROBENOCTURNALFULL(platform, lang) \ + { "nocIll", \ + 0, \ + AD_ENTRY1s("mug0.dat", NULL, -1), \ + lang, \ + platform, \ + ADGF_NO_FLAGS, \ + GUIO1(GUIO_NONE) } + +#define PROBENOCTURNALLANG(lang) \ + PROBENOCTURNALFULL(Common::kPlatformWindows, lang), \ + PROBENOCTURNALFULL(Common::kPlatformLinux, lang), \ + PROBENOCTURNALFULL(Common::kPlatformPC98, lang), \ + PROBENOCTURNALFULL(Common::kPlatformMacintosh, lang) + +#define PROBENOCTURNAL() \ +PROBENOCTURNALLANG(Common::EN_ANY), \ + PROBENOCTURNALLANG(Common::JA_JPN), \ + PROBENOCTURNALLANG(Common::PT_BRA), \ +PROBENOCTURNALLANG(Common::PT_POR), \ + PROBENOCTURNALLANG(Common::RU_RUS), \ + PROBENOCTURNALLANG(Common::FR_FRA), \ +PROBEJASTUSANAME("noctIll") + +#define PROBESAGARA() \ + PROBESUFFULL("sagara", "sagara", Common::kPlatformWindows, Common::EN_ANY), \ + PROBESUFFULL("sagara", "sagara", Common::kPlatformWindows, Common::JA_JPN) + +#define PROBECRESCENDOLANG(lang) \ + PROBESUFFULL("cres", "cres", Common::kPlatformWindows, lang) + +#define PROBECRESCENDO() \ + PROBECRESCENDOLANG(Common::EN_ANY), \ + PROBECRESCENDOLANG(Common::JA_JPN), \ + PROBECRESCENDOLANG(Common::RU_RUS), \ + PROBECRESCENDOLANG(Common::ZH_ANY) + +#define PROBEYUKI() \ + PROBESUFFULL("yuki", "yuki", Common::kPlatformWindows, Common::EN_ANY), \ + PROBESUFFULL("yuki", "yuki", Common::kPlatformWindows, Common::JA_JPN) + +#define PROBEHITOMI() \ + PROBESUFFULL("hitomi", "hitomi", Common::kPlatformWindows, Common::EN_ANY), \ + PROBESUFFULL("hitomi", "hitomi", Common::kPlatformWindows, Common::JA_JPN) + +#define PROBEKONEKO() \ + PROBESUFFULL("koneko", "koneko", Common::kPlatformWindows, Common::EN_ANY), \ + PROBESUFFULL("koneko", "koneko", Common::kPlatformWindows, Common::JA_JPN) + +#define PROBEMESIA() \ + PROBESUFFULL("mesia", "mesia", Common::kPlatformWindows, Common::EN_ANY), \ + PROBESUFFULL("mesia", "mesia", Common::kPlatformWindows, Common::JA_JPN), \ + PROBESUFFULL("mesia", "mesia", Common::kPlatformWindows, Common::RU_RUS) + +#define PROBETRUELOVEFULL(platform, lang) \ + { "truelove", \ + 0, \ + {{"eff", 0, NULL, -1}, \ + {"mrs", 0, NULL, -1}, \ + {"date", 0, NULL, -1}, \ + {"datg", 0, NULL, -1}, \ + AD_LISTEND}, \ + lang, \ + platform, \ + ADGF_NO_FLAGS, \ + GUIO1(GUIO_NONE) } + +#define PROBETRUELOVELANG(lang) \ + PROBETRUELOVEFULL(Common::kPlatformWindows, lang), \ + PROBETRUELOVEFULL(Common::kPlatformPC98, lang) + +#define PROBETRULOVE() \ + PROBETRUELOVELANG(Common::EN_ANY), \ + PROBETRUELOVELANG(Common::JA_JPN), \ + PROBETRUELOVELANG(Common::PT_BRA), \ + PROBETRUELOVELANG(Common::PT_POR), \ + PROBETRUELOVELANG(Common::DE_DEU), \ + PROBETRUELOVELANG(Common::ES_ESP), \ + PROBETRUELOVELANG(Common::RU_RUS) + +#define PROBERIOCHIPARC(name, platform, lang) \ + { name, 0, {{"rio.arc", 0, NULL, -1}, {"chio.arc", 0, NULL, -1}, AD_LISTEND}, lang, platform, ADGF_NO_FLAGS, GUIO1(GUIO_NONE) } + +#define PROBEYUMEMIRU() \ + PROBERIOCHIPARC("yumemiru", Common::kPlatformWindows, Common::EN_ANY), \ + PROBERIOCHIPARC("yumemiru", Common::kPlatformWindows, Common::JA_JPN), \ + PROBERIOCHIPARC("yumemiru", Common::kPlatformWindows, Common::ZH_ANY), \ + PROBERIOCHIPARC("yumemiru", Common::kPlatformWindows, Common::ES_ESP), \ + PROBERIOCHIPARC("yumemiru", Common::kPlatformWindows, Common::RU_RUS), \ + PROBERIOCHIPARC("yumemiru", Common::kPlatformWindows, Common::KO_KOR) + +#define PROBECRITPOINT() \ + PROBERIOCHIPARC("criticalpoint", Common::kPlatformWindows, Common::EN_ANY), \ + PROBERIOCHIPARC("criticalpoint", Common::kPlatformWindows, Common::JA_JPN), \ + PROBERIOCHIPARC("criticalpoint", Common::kPlatformWindows, Common::RU_RUS) + +#define PROBETOKIMEKI() \ + {"tokimeki", 0, {{"scene00.bdt", 0, NULL, -1}, {"353-103.zbm", 0, NULL, -1}, {"indexw.dat", 0, NULL, -1}, AD_LISTEND}, Common::EN_ANY, Common::kPlatformWindows, ADGF_NO_FLAGS, GUIO1(GUIO_NONE)}, \ + { "tokimeki", 0, {{"scene00.bdt", 0, NULL, -1}, {"353-103.zbm", 0, NULL, -1}, {"indexw.dat", 0, NULL, -1}, AD_LISTEND}, Common::JA_JPN, Common::kPlatformWindows, ADGF_NO_FLAGS, GUIO1(GUIO_NONE) } + +#define PROBEXCH1() \ + {"xch1", 0, {{"scene00.bdt", 0, NULL, -1}, {"207-30l2.zbm", 0, NULL, -1}, {"indexw.dat", 0, NULL, -1}, AD_LISTEND}, Common::EN_ANY, Common::kPlatformWindows, ADGF_NO_FLAGS, GUIO1(GUIO_NONE)}, \ + {"xch1", 0, {{"scene00.bdt", 0, NULL, -1}, {"207-30l2.zbm", 0, NULL, -1}, {"indexw.dat", 0, NULL, -1}, AD_LISTEND}, Common::JA_JPN, Common::kPlatformWindows, ADGF_NO_FLAGS, GUIO1(GUIO_NONE)}, \ + { \ + "xch1", 0, {{"scene00.bdt", 0, NULL, -1}, {"207-30l2.zbm", 0, NULL, -1}, {"indexw.dat", 0, NULL, -1}, AD_LISTEND}, \ + Common::RU_RUS, Common::kPlatformWindows, ADGF_NO_FLAGS, GUIO1(GUIO_NONE) \ + } + +#define PROBEXCH3() \ + { "xch3", 0, {{"xc3.sce", 0, NULL, -1}, AD_LISTEND}, Common::EN_ANY, Common::kPlatformWindows, ADGF_NO_FLAGS, GUIO1(GUIO_NONE) },\ + { "xch3", 0, {{"xc3.sce", 0, NULL, -1}, AD_LISTEND}, Common::JA_JPN, Common::kPlatformWindows, ADGF_NO_FLAGS, GUIO1(GUIO_NONE) },\ + { "xch3", 0, {{"xc3.sce", 0, NULL, -1}, AD_LISTEND}, Common::RU_RUS, Common::kPlatformWindows, ADGF_NO_FLAGS, GUIO1(GUIO_NONE) } + +namespace VileVN { + +static const ADGameDescription gameDescriptions[] = { + PROBEMAYCLUB(), + PROBENOCTURNAL(), + PROBECRESCENDO(), + PROBESAGARA(), + PROBEYUKI(), + PROBEKANAOKA(), + PROBEHITOMI(), + PROBEKONEKO(), + PROBEMESIA(), + PROBEJASTUSA(), + PROBEDIVIDEAD(), + PROBETRULOVE(), + PROBEYUMEMIRU(), + PROBECRITPOINT(), + PROBETOKIMEKI(), + PROBEXCH1(), + PROBEXCH3(), + + AD_TABLE_END_MARKER}; + +} // End of namespace VileVN + +static const PlainGameDescriptor VileVNGames[] = { + {"mayclub", "May Club", "WIP", "https://vndb.org/v190"}, + {"mayclub2", "May Club 2", "WIP", "https://vndb.org/v190"}, + {"nocIll", "Mugen Yasoukyoku", "WIP", "https://vndb.org/v190"}, + {"cres", "Crescendo ~Eien da to Omotte Ita Ano Koro~", "WIP", "https://vndb.org/v29"}, + {"sagara", "Sagara-sanchi no Etsuraku Life", "WIP", "https://vndb.org/v46"}, + {"yuki", "Yuki Sakura", "WIP", "https://vndb.org/v71"}, + {"kanaoka", "Kana ~Imouto~", "WIP", "https://vndb.org/v2"}, + {"hitomi", "Gimai - Hitomi", "WIP", "https://vndb.org/v31"}, + {"koneko", "Koneko Doumei", "WIP", "https://vndb.org/v153"}, + {"mesia", "Meshimase Idol", "WIP", "https://vndb.org/v141"}, + {"meisou", "Meisou Toshi", "WIP", "https://vndb.org/v843"}, + {"sakura", "Sakura no Kisetsu", "WIP", "https://vndb.org/v206"}, + {"sanshi", "San Shimai", "WIP", "https://vndb.org/v113"}, + {"dividead", "Divi-Dead", "WIP", "https://vndb.org/v119"}, + {"truelove", "True Love ~Jun'ai Monogatari~", "WIP", "https://vndb.org/v241"}, + {"yumemiru", "Yume Miru Kusuri", "WIP", "https://vndb.org/v44"}, + {"criticalpoint", "Rinkaiten ~Critical Point~", "WIP", "https://vndb.org/v145"}, + {"tokimeki", "Tokimeki Check-In!", "WIP", "https://vndb.org/v111"}, + {"xch1", "X-Change 1", "WIP", "https://vndb.org/v43"}, + {"xch3", "X-Change 3", "WIP", "https://vndb.org/v129"}, + {0, 0, 0, 0}}; diff --git a/engines/vileVN/module.mk b/engines/vileVN/module.mk index c113a9bba0..d29222e6fe 100644 --- a/engines/vileVN/module.mk +++ b/engines/vileVN/module.mk @@ -2,6 +2,7 @@ MODULE := engines/vileVN MODULE_OBJS := \ detection.o \ + vileVN.o \ MODULE_DIRS += \ engines/vileVN diff --git a/engines/vileVN/vile.cpp b/engines/vileVN/vile.cpp index a875d666da..ef9f537652 100644 --- a/engines/vileVN/vile.cpp +++ b/engines/vileVN/vile.cpp @@ -1,172 +1,3 @@ -bool ViLE::ProbeIdols(uString Path){ - // Check for key files - LogVerbose("Probing for Idols Galore!:"); - bool retval=false; - if(ProbeSUF(Path,"mesia")){ - retval=true; - } - else if(ProbeResource(Path,"isf") && ProbeResource(Path,"mesiaus.suf")){ - // The download edition has an annoying typo in the descriptor file - INIFile *inifile=new INIFile(false); - if(inifile->ReadFile(EDL_Realname(Path+"mesiaus.suf"))){ - uString gamekey,gametitle="unknown"; - if(inifile->Get("Key",gamekey)){ - if(ProbeString(gamekey,"mesiaius")){ - retval=true; - } - } - } - } - return retval; -} - -bool ViLE::ProbeJUMC(uString Path){ - // Check for key files - LogVerbose("Probing for JAST USA Memorial Collection:"); - return (ProbeResource(Path,"data/images.pck") && - ProbeResource(Path,"data/data.pck") && - ProbeResource(Path,"data/frames.pck")); -} - -bool ViLE::ProbeDiviDead(uString Path){ - // Check for key files - LogVerbose("Probing for DiviDead:"); - return (ProbeResource(Path,"sg.dl1") && - ProbeResource(Path,"wv.dl1")); -} - -bool ViLE::ProbeTrueLove(uString Path){ - // Check for key files - LogVerbose("Probing for True love:"); - return (ProbeResource(Path,"eff") && - ProbeResource(Path,"mrs") && - (ProbeResource(Path,"date") || - ProbeResource(Path,"datg"))); -} - -bool ViLE::ProbeYumeMiruKusuri(uString Path){ - // Check for key files - LogVerbose("Probing for Yume Miru Kusuri:"); - return (ProbeResource(Path,"rio.arc") && - ProbeResource(Path,"chip.arc") && - (ProbeSize(Path+"rio.arc",1828524) || - ProbeSize(Path+"rio.arc",1828457))); -} - -bool ViLE::ProbeCriticalPoint(uString Path){ - // Check for key files - LogVerbose("Probing for Critical Point:"); - return (ProbeResource(Path,"rio.arc") && - ProbeResource(Path,"chip.arc") && - ProbeSize(Path+"rio.arc",986745)); -} - -bool ViLE::ProbeTokimeki(uString Path){ - // Check for key files - LogVerbose("Probing for Tokimeki Check-in!:"); - return (ProbeResource(Path,"scene00.bdt") && - ProbeResource(Path,"353-103.zbm") && - ProbeResource(Path,"indexw.dat")); -} - -bool ViLE::ProbeXChange1(uString Path){ - // Check for key files - LogVerbose("Probing for XChange 1:"); - return (ProbeResource(Path,"scene00.bdt") && - ProbeResource(Path,"207-30l2.zbm") && - ProbeResource(Path,"index.dat")); -} - -bool ViLE::ProbeXChange3(uString Path){ - // Check for key files - LogVerbose("Probing for XChange 3:"); - return (ProbeResource(Path,"xc3.sce") && - ProbeResource(Path,"voice/xc3.pck")); -} - -/*! \brief Checks existence of resource file and logs verbosely - * \param Path Directory - * \param Resource Filename path relative to Path - * \return True if file exists - */ -bool ViLE::ProbeResource(uString Path,uString Resource){ - uString path=EDL_Realname(Path+Resource); - bool retval=EDL_ReadableFile(path); - LogVerbose("\t%-40s%s",path.c_str(),retval?"PASS":"FAIL"); - return retval; -} - -/*! \brief Checks if two strings matches and logs verbosely - * \param S1 String - * \param S2 String to compare with - * \return True if the strings matches (case insensitive) - */ -bool ViLE::ProbeString(uString S1,uString S2){ - S1=EDL_Lower(S1); - S2=EDL_Lower(S2); - bool retval=(S1==S2); - uString msg=S1+uString(" == ")+S2; - LogVerbose("\t%-40s%s",msg.c_str(),retval?"PASS":"FAIL"); - return retval; -} - -/*! \brief Checks size of a file and logs verbosely - * \param Path Path to file - * \param Size Expected size - * \return True if file exists and size matches - */ -bool ViLE::ProbeSize(uString Path,unsigned int Size){ - bool retval=false; - int compare=-1; - uString path=EDL_Realname(Path); - FILE *test=fopen(path.c_str(),"rb"); - if(test){ - fseek(test,0,SEEK_END); - compare=ftell(test); - retval=(compare==(int)Size); - fclose(test); - } - LogVerbose("\t%-40s%d/%d",path.c_str(),compare,Size); - return retval; -} - -/*! \brief Confirms a IkuraGDL title using a SUF file - * \param Path Folder to load resources from - * \param Key Key to confirm - * \return True if title resources was confirmed - */ -bool ViLE::ProbeSUF(uString Path,uString Key){ - // Check for key files - bool retval=0; - bool isf=ProbeResource(Path,"ggd") && ProbeResource(Path,"isf"); - bool drs=ProbeResource(Path,"drsgrp") && ProbeResource(Path,"drssnr"); - if(isf || drs){ - // Get SUF file - uString sufname; - if(ProbeResource(Path,"game.suf")) sufname="game.suf"; - else if(ProbeResource(Path,Key+".suf")) sufname=Key+".suf"; - else if(ProbeResource(Path,Key+"us.suf")) sufname=Key+"us.suf"; - else if(ProbeResource(Path,Key+"ml.suf")) sufname=Key+"ml.suf"; - - // Confirm title - if(sufname.length()){ - INIFile *inifile=new INIFile(false); - LogVerbose("Parsing SUF: %s",sufname.c_str()); - if(inifile->ReadFile(EDL_Realname(Path+sufname))){ - uString gamekey,gametitle="unknown"; - if(inifile->Get("Key",gamekey)){ - if(ProbeString(gamekey,Key) || - ProbeString(gamekey,Key+"us") || - ProbeString(gamekey,Key+"ml")){ - retval=true; - } - } - } - delete inifile; - } - } - return retval; -} void ViLE::RunEngine(EngineVN *engine){ // Load screen surface and set a caption @@ -860,18 +691,3 @@ bool ViLE::XDec(uString Archive,Stringlist *List){ } return retval; } - -void ViLE::Error(uString Title,uString Message){ - // Report failed loading - EngineVN *evn=new EngineVN(640,480); - while(evn->DestroyAnimation()); - Widget *widget=new Widget(0,0,640,480); - widget->Fill(0xFFFFFFFF); - Fatal *fatal=new Fatal(evn,Title,Message); - evn->DestroyLayer(VL_DIALOG); - evn->AddWidget(widget,VL_BACKGROUND); - evn->AddWidget(fatal,VL_DIALOG); - RunEngine(evn); -} - - diff --git a/engines/vileVN/vileVN.cpp b/engines/vileVN/vileVN.cpp new file mode 100644 index 0000000000..da1b9cc3c5 --- /dev/null +++ b/engines/vileVN/vileVN.cpp @@ -0,0 +1,97 @@ + + + +#include "vileVN/vileVN.h" +#include "common/events.h" + +namespace VileVN +{ + +VileVNEngine::VileVNEngine(OSystem *syst, const ADGameDescription *desc) + : Engine(syst), _gameDescription(desc), _console(nullptr) +{ + // Put your engine in a sane state, but do nothing big yet; + // in particular, do not load data from files; rather, if you + // need to do such things, do them from run(). + + // Do not initialize graphics here + // Do not initialize audio devices here + + // However this is the place to specify all default directories + const Common::FSNode gameDataDir(ConfMan.get("path")); + // Here is the right place to set up the engine specific debug channels + DebugMan.addDebugChannel(kVileVNDebug, "example", "this is just an example for a engine specific debug channel"); + DebugMan.addDebugChannel(kVileVNDebug2, "example2", "also an example"); + + // Don't forget to register your random source + _rnd = new Common::RandomSource("vileVN"); + + debug("VileVNEngine::VileVNEngine"); +} + +VileVNEngine::~VileVNEngine() +{ + debug("VileVNEngine::~VileVNEngine"); + + // Dispose your resources here + delete _rnd; + + // Remove all of our debug levels here + DebugMan.clearAllDebugChannels(); +} + +Common::Error VileVNEngine::run() +{ + // Initialize graphics using following: + + + + + + Common::List formats = g_system->getSupportedFormats(); + + initGraphics(640, 480, formats); + + Graphics::PixelFormat format = g_system->getScreenFormat(); + + Common::Event e; + while (!shouldQuit()) + { + g_system->getEventManager()->pollEvent(e); + g_system->delayMillis(10); + } + + // You could use backend transactions directly as an alternative, + // but it isn't recommended, until you want to handle the error values + // from OSystem::endGFXTransaction yourself. + // This is just an example template: + //_system->beginGFXTransaction(); + // // This setup the graphics mode according to users seetings + // initCommonGFX(false); + // + // // Specify dimensions of game graphics window. + // // In this example: 320x200 + // _system->initSize(320, 200); + //FIXME: You really want to handle + //OSystem::kTransactionSizeChangeFailed here + //_system->endGFXTransaction(); + + // Create debugger console. It requires GFX to be initialized + _console = new Console(this); + + // Additional setup. + debug("VileVNEngine::init"); + + // Your main even loop should be (invoked from) here. + debug("VileVNEngine::go: Hello, World!"); + + // This test will show up if -d1 and --debugflags=example are specified on the commandline + debugC(1, kVileVNDebug, "Example debug call"); + + // This test will show up if --debugflags=example or --debugflags=example2 or both of them and -d3 are specified on the commandline + debugC(3, kVileVNDebug | kVileVNDebug2, "Example debug call two"); + + return Common::kNoError; +} + +} // End of namespace VileVN diff --git a/engines/vileVN/vileVN.h b/engines/vileVN/vileVN.h new file mode 100644 index 0000000000..998e31c3eb --- /dev/null +++ b/engines/vileVN/vileVN.h @@ -0,0 +1,73 @@ +#ifndef VileVN_H +#define VileVN_H + +#include "common/random.h" +#include "engines/engine.h" +#include "common/file.h" +#include "gui/debugger.h" +#include "common/scummsys.h" + +#include "common/system.h" +#include "common/config-manager.h" +#include "common/debug.h" +#include "common/debug-channels.h" +#include "common/error.h" +#include "common/file.h" +#include "common/fs.h" +#include "common/str.h" +#include "common/hex.h" + +#include "engines/util.h" + +#include "audio/audiostream.h" +#include "audio/mixer.h" +#include "audio/decoders/wave.h" + +struct ADGameDescription; + +namespace VileVN { + + +class Console; + +// our engine debug channels +enum { + kVileVNDebug = 1 << 0, + kVileVNDebug2 = 1 << 1 + // next new channel must be 1 << 2 (4) + // the current limitation is 32 debug channels (1 << 31 is the last one) +}; + typedef Common::HashMap, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> GameArchives; + +class VileVNEngine : public Engine { +public: + VileVNEngine(OSystem *syst, const ADGameDescription *gameDesc); + ~VileVNEngine(); + + + + virtual Common::Error run(); + + // Detection related functions + const ADGameDescription *_gameDescription; + const char *getGameId() const; + Common::Platform getPlatform() const; + +private: + Console *_console; + + Audio::SoundHandle _shandle; + // We need random numbers + Common::RandomSource *_rnd; +}; + +// Example console class +class Console : public GUI::Debugger { +public: + Console(VileVNEngine *vm) {} + virtual ~Console(void) {} +}; + +} // End of namespace VileVN + +#endif \ No newline at end of file